home *** CD-ROM | disk | FTP | other *** search
/ Aminet 43 / Aminet 43 (2001)(GTI - Schatztruhe)[!][Jun 2001].iso / Aminet / comm / tcp / smbfs.lha / source / main.c < prev    next >
C/C++ Source or Header  |  2001-04-07  |  116KB  |  5,629 lines

  1. /*
  2.  * $Id: main.c,v 1.64 2001/04/07 11:32:29 olsen Exp $
  3.  *
  4.  * :ts=4
  5.  *
  6.  * SMB file system wrapper for AmigaOS, using the AmiTCP V3 API
  7.  *
  8.  * Copyright (C) 2000-2001 by Olaf `Olsen' Barthel <olsen@sourcery.han.de>
  9.  *
  10.  * This program is free software; you can redistribute it and/or modify
  11.  * it under the terms of the GNU General Public License as published by
  12.  * the Free Software Foundation; either version 2 of the License, or
  13.  * (at your option) any later version.
  14.  *
  15.  * This program is distributed in the hope that it will be useful,
  16.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  17.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  18.  * GNU General Public License for more details.
  19.  *
  20.  * You should have received a copy of the GNU General Public License
  21.  * along with this program; if not, write to the Free Software
  22.  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  23.  *
  24.  * smbfs arbeitsgruppe pcguest debug=2 //sourcery/all
  25.  */
  26.  
  27. #include "system_headers.h"
  28. #include "assert.h"
  29.  
  30. /****************************************************************************/
  31.  
  32. #include "smb_abstraction.h"
  33.  
  34. /****************************************************************************/
  35.  
  36. #include "smbfs_rev.h"
  37. STRPTR Version = VERSTAG;
  38.  
  39. /****************************************************************************/
  40.  
  41. #define SAME (0)
  42. #define OK (0)
  43. #define NOT !
  44. #define ZERO ((BPTR)NULL)
  45.  
  46. /****************************************************************************/
  47.  
  48. #ifdef __SASC
  49. #define FAR __far
  50. #define ASM __asm
  51. #define REG(x) register __ ## x
  52. #define INLINE __inline
  53. #else
  54. #define FAR
  55. #define ASM
  56. #define REG(x)
  57. #define INLINE
  58. #endif /* __SASC */
  59.  
  60. /****************************************************************************/
  61.  
  62. #define UNIX_TIME_OFFSET 252460800
  63. #define MAX_FILENAME_LEN 256
  64.  
  65. /****************************************************************************/
  66.  
  67. #define SMB_ROOT_DIR_NAME    "\\"
  68. #define SMB_PATH_SEPARATOR    '\\'
  69.  
  70. /****************************************************************************/
  71.  
  72. typedef STRPTR    KEY;
  73. typedef LONG *    NUMBER;
  74. typedef LONG    SWITCH;
  75.  
  76. /****************************************************************************/
  77.  
  78. struct FileNode
  79. {
  80.     struct MinNode        fn_MinNode;
  81.     struct FileHandle *    fn_Handle;
  82.     LONG                fn_Offset;
  83.     LONG                fn_Mode;
  84.     smba_file_t *        fn_File;
  85.     STRPTR                fn_FullName;
  86. };
  87.  
  88. struct LockNode
  89. {
  90.     struct MinNode    ln_MinNode;
  91.     struct FileLock    ln_FileLock;
  92.     smba_file_t *    ln_File;
  93.     BOOL            ln_RestartExamine;
  94.     UWORD            ln_Pad;
  95.     STRPTR            ln_FullName;
  96. };
  97.  
  98. /****************************************************************************/
  99.  
  100. /* These are in amiga.lib */
  101. APTR ASM AsmCreatePool(REG(d0) ULONG memFlags,REG(d1) ULONG puddleSize,REG(d2) ULONG threshSize,REG(a6) struct Library * SysBase);
  102. VOID ASM AsmDeletePool(REG(a0) APTR poolHeader,REG(a6) struct Library * SysBase);
  103. APTR ASM AsmAllocPooled(REG(a0) APTR poolHeader,REG(d0) ULONG memSize,REG(a6) struct Library * SysBase);
  104. VOID ASM AsmFreePooled(REG(a0) APTR poolHeader,REG(a1) APTR memory,REG(d0) ULONG memSize,REG(a6) struct Library * SysBase);
  105.  
  106. /****************************************************************************/
  107.  
  108. /* Forward declarations for local routines. */
  109. STATIC VOID DisplayErrorList(VOID);
  110. STATIC VOID AddError(STRPTR fmt, va_list args);
  111. STATIC LONG CVSPrintf(STRPTR format_string, va_list args);
  112. STATIC VOID VSPrintf(STRPTR buffer, STRPTR formatString, va_list args);
  113. STATIC VOID SendDiskChange(ULONG class);
  114. STATIC struct FileNode *FindFileNode(STRPTR name, struct FileNode *skip);
  115. STATIC struct LockNode *FindLockNode(STRPTR name, struct LockNode *skip);
  116. STATIC LONG CheckAccessModeCollision(STRPTR name, LONG mode);
  117. STATIC LONG NameAlreadyInUse(STRPTR name);
  118. STATIC BOOL IsReservedName(STRPTR name);
  119. STATIC LONG MapErrnoToIoErr(int error);
  120. STATIC VOID INLINE TranslateBName(UBYTE *name, UBYTE *map);
  121. STATIC VOID INLINE TranslateCName(UBYTE *name, UBYTE *map);
  122. STATIC BOOL ReallyRemoveDosEntry(struct DosList *entry);
  123. STATIC VOID Cleanup(VOID);
  124. STATIC BOOL Setup(STRPTR program_name, STRPTR service, STRPTR workgroup, STRPTR username, STRPTR opt_password, BOOL opt_changecase, STRPTR opt_clientname, STRPTR opt_servername, int opt_cachesize, STRPTR device_name, STRPTR volume_name, STRPTR translation_file);
  125. STATIC VOID INLINE ConvertBString(LONG max_len, STRPTR cstring, APTR bstring);
  126. STATIC VOID INLINE ConvertCString(LONG max_len, APTR bstring, STRPTR cstring);
  127. STATIC LONG BuildFullName(STRPTR parent_name, STRPTR name, STRPTR *result_ptr);
  128. STATIC BPTR Action_Parent(struct FileLock *parent, LONG *error_ptr);
  129. STATIC LONG Action_DeleteObject(struct FileLock *parent, APTR bcpl_name, LONG *error_ptr);
  130. STATIC BPTR Action_CreateDir(struct FileLock *parent, APTR bcpl_name, LONG *error_ptr);
  131. STATIC BPTR Action_LocateObject(struct FileLock *parent, APTR bcpl_name, LONG mode, LONG *error_ptr);
  132. STATIC BPTR Action_CopyDir(struct FileLock *lock, LONG *error_ptr);
  133. STATIC LONG Action_FreeLock(struct FileLock *lock, LONG *error_ptr);
  134. STATIC LONG Action_SameLock(struct FileLock *lock1, struct FileLock *lock2, LONG *error_ptr);
  135. STATIC LONG Action_SetProtect(struct FileLock *parent, APTR bcpl_name, LONG mask, LONG *error_ptr);
  136. STATIC LONG Action_RenameObject(struct FileLock *source_lock, APTR source_bcpl_name, struct FileLock *destination_lock, APTR destination_bcpl_name, LONG *error_ptr);
  137. STATIC LONG Action_DiskInfo(struct InfoData *id, LONG *error_ptr);
  138. STATIC LONG Action_Info(struct FileLock *lock, struct InfoData *id, LONG *error_ptr);
  139. STATIC LONG Action_ExamineObject(struct FileLock *lock, struct FileInfoBlock *fib, LONG *error_ptr);
  140. STATIC BOOL NameIsAcceptable(STRPTR name, LONG max_len);
  141. STATIC LONG Action_ExamineNext(struct FileLock *lock, struct FileInfoBlock *fib, LONG *error_ptr);
  142. STATIC LONG Action_ExamineAll(struct FileLock *lock, struct ExAllData *ed, ULONG size, ULONG type, struct ExAllControl *eac, LONG *error_ptr);
  143. STATIC LONG Action_Find(LONG action, struct FileHandle *fh, struct FileLock *parent, APTR bcpl_name, LONG *error_ptr);
  144. STATIC LONG Action_Read(struct FileNode *fn, APTR mem, LONG length, LONG *error_ptr);
  145. STATIC LONG Action_Write(struct FileNode *fn, APTR mem, LONG length, LONG *error_ptr);
  146. STATIC LONG Action_End(struct FileNode *fn, LONG *error_ptr);
  147. STATIC LONG Action_Seek(struct FileNode *fn, LONG position, LONG mode, LONG *error_ptr);
  148. STATIC LONG Action_SetFileSize(struct FileNode *fn, LONG position, LONG mode, LONG *error_ptr);
  149. STATIC LONG Action_SetDate(struct FileLock *parent, APTR bcpl_name, struct DateStamp *ds, LONG *error_ptr);
  150. STATIC LONG Action_ExamineFH(struct FileNode *fn, struct FileInfoBlock *fib, LONG *error_ptr);
  151. STATIC BPTR Action_ParentFH(struct FileNode *fn, LONG *error_ptr);
  152. STATIC BPTR Action_CopyDirFH(struct FileNode *fn, LONG *error_ptr);
  153. STATIC LONG Action_FHFromLock(struct FileHandle *fh, struct FileLock *fl, LONG *error_ptr);
  154. STATIC LONG Action_RenameDisk(APTR bcpl_name, LONG *error_ptr);
  155. STATIC LONG Action_ChangeMode(LONG type, APTR object, LONG new_mode, LONG *error_ptr);
  156. STATIC LONG Action_WriteProtect(LONG flag, ULONG key, LONG *error_ptr);
  157. STATIC LONG Action_MoreCache(LONG buffer_delta, LONG *error_ptr);
  158. STATIC LONG Action_SetComment(struct FileLock *parent, APTR bcpl_name, APTR bcpl_comment, LONG *error_ptr);
  159. STATIC VOID HandleFileSystem(STRPTR device_name, STRPTR volume_name, STRPTR service_name);
  160.  
  161. /****************************************************************************/
  162.  
  163. VOID ReportError(STRPTR fmt,...);
  164. VOID SPrintf(STRPTR buffer, STRPTR formatString,...);
  165.  
  166. /****************************************************************************/
  167.  
  168. struct Library *            SysBase;
  169. struct Library *            DOSBase;
  170. struct Library *            UtilityBase;
  171. struct Library *            SocketBase;
  172. struct Library *            LocaleBase;
  173. struct Locale *                Locale;
  174. struct Device *                TimerBase;
  175. struct timerequest            TimerRequest;
  176. struct Library *            IconBase;
  177.  
  178. /****************************************************************************/
  179.  
  180. int                            errno;
  181. int                            h_errno;
  182.  
  183. /****************************************************************************/
  184.  
  185. STATIC struct DosList *        DeviceNode;
  186. STATIC BOOL                    DeviceNodeAdded;
  187. STATIC struct DosList *        VolumeNode;
  188. STATIC BOOL                    VolumeNodeAdded;
  189. STATIC struct MsgPort *        FileSystemPort;
  190.  
  191. STATIC smba_server_t *        ServerData;
  192.  
  193. STATIC BOOL                    Quit;
  194. STATIC BOOL                    Quiet;
  195. STATIC BOOL                    CaseSensitive;
  196. STATIC BOOL                    OmitHidden;
  197.  
  198. STATIC BOOL                    WriteProtected;
  199. STATIC ULONG                WriteProtectKey;
  200.  
  201. STATIC struct MinList        FileList;
  202. STATIC struct MinList        LockList;
  203.  
  204. STATIC APTR                    MemoryPool;
  205.  
  206. STATIC struct RDArgs *        Parameters;
  207. STATIC struct DiskObject *    Icon;
  208.  
  209. STATIC struct WBStartup *     WBStartup;
  210.  
  211. STATIC struct MinList        ErrorList;
  212.  
  213. STATIC STRPTR                NewProgramName;
  214.  
  215. STATIC BOOL                    TranslateNames;
  216. STATIC UBYTE                A2M[256];
  217. STATIC UBYTE                M2A[256];
  218.  
  219. /****************************************************************************/
  220.  
  221. extern struct Library * FAR    AbsExecBase;
  222.  
  223. /****************************************************************************/
  224.  
  225. LONG
  226. Main(VOID)
  227. {
  228.     struct
  229.     {
  230.         KEY        Workgroup;
  231.         KEY        UserName;
  232.         KEY        Password;
  233.         SWITCH    ChangeCase;
  234.         SWITCH    CaseSensitive;
  235.         SWITCH    OmitHidden;
  236.         SWITCH    Quiet;
  237.         KEY        ClientName;
  238.         KEY        ServerName;
  239.         KEY        DeviceName;
  240.         KEY        VolumeName;
  241.         NUMBER    CacheSize;
  242.         NUMBER    DebugLevel;
  243.         KEY        TranslationFile;
  244.         KEY        Service;
  245.     } args;
  246.  
  247.     STRPTR cmd_template =
  248.         "DOMAIN=WORKGROUP/K,"
  249.         "USER=USERNAME/K,"
  250.         "PASSWORD/K,"
  251.         "CHANGECASE/S,"
  252.         "CASE=CASESENSITIVE/S,"
  253.         "OMITHIDDEN/S,"
  254.         "QUIET/S,"
  255.         "CLIENT=CLIENTNAME/K,"
  256.         "SERVER=SERVERNAME/K,"
  257.         "DEVICE=DEVICENAME/K,"
  258.         "VOLUME=VOLUMENAME/K,"
  259.         "CACHE=CACHESIZE/N/K,"
  260.         "DEBUGLEVEL=DEBUG/N/K,"
  261.         "TRANSLATE=TRANSLATIONFILE/K,"
  262.         "SERVICE/A";
  263.  
  264.     struct Process * this_process;
  265.     UBYTE program_name[MAX_FILENAME_LEN];
  266.     LONG result;
  267.     LONG number;
  268.     LONG cache_size = 0;
  269.     char env_workgroup_name[17];
  270.     char env_user_name[64];
  271.     char env_password[64];
  272.  
  273.     geta4();
  274.  
  275.     SysBase = AbsExecBase;
  276.  
  277.     /* Pick up the Workbench startup message, if
  278.      * there is one.
  279.      */
  280.     this_process = (struct Process *)FindTask(NULL);
  281.     if(this_process->pr_CLI == ZERO)
  282.     {
  283.         WaitPort(&this_process->pr_MsgPort);
  284.         WBStartup = (struct WBStartup *)GetMsg(&this_process->pr_MsgPort);
  285.     }
  286.     else
  287.     {
  288.         WBStartup = NULL;
  289.     }
  290.  
  291.     /* Don't emit any debugging output before we are ready. */
  292.     SETDEBUGLEVEL(0);
  293.  
  294.     /* Open the libraries we need and check
  295.      * whether we could get them.
  296.      */
  297.     DOSBase = OpenLibrary("dos.library",0);
  298.     UtilityBase = OpenLibrary("utility.library",37);
  299.  
  300.     if(UtilityBase == NULL || DOSBase == NULL || DOSBase->lib_Version < 37)
  301.     {
  302.         /* Complain loudly if this is not the operating
  303.          * system version we expected.
  304.          */
  305.         if(DOSBase != NULL && this_process->pr_CLI != ZERO)
  306.         {
  307.             STRPTR msg = "AmigaOS 2.04 or higher required.\n";
  308.  
  309.             Write(Output(),msg,strlen(msg));
  310.         }
  311.  
  312.         Cleanup();
  313.  
  314.         return(RETURN_FAIL);
  315.     }
  316.  
  317.     /* This needs to be set up properly for error report
  318.      * to work.
  319.      */
  320.     NewList((struct List *)&ErrorList);
  321.  
  322.     memset(&args,0,sizeof(args));
  323.  
  324.     /* If this program was launched from Workbench,
  325.      * parameter passing will have to be handled
  326.      * differently.
  327.      */
  328.     if(WBStartup != NULL)
  329.     {
  330.         STRPTR str;
  331.         BPTR old_dir;
  332.         LONG n;
  333.  
  334.         if(WBStartup->sm_NumArgs > 1)
  335.             n = 1;
  336.         else
  337.             n = 0;
  338.  
  339.         /* Get the name of the program, as it was launched
  340.          * from Workbench. We actually prefer the name of
  341.          * the first project file, if there is one.
  342.          */
  343.         strncpy(program_name,WBStartup->sm_ArgList[n].wa_Name,sizeof(program_name)-1);
  344.         program_name[sizeof(program_name)-1] = '\0';
  345.  
  346.         /* Now open icon.library and read that icon. */
  347.         IconBase = OpenLibrary("icon.library",0);
  348.         if(IconBase == NULL)
  349.         {
  350.             ReportError("Could not open 'icon.library'.");
  351.  
  352.             Cleanup();
  353.  
  354.             return(RETURN_FAIL);
  355.         }
  356.  
  357.         old_dir = CurrentDir(WBStartup->sm_ArgList[n].wa_Lock);
  358.         Icon = GetDiskObject(WBStartup->sm_ArgList[n].wa_Name);
  359.         CurrentDir(old_dir);
  360.  
  361.         if(Icon == NULL)
  362.         {
  363.             ReportError("Icon not found.");
  364.  
  365.             Cleanup();
  366.  
  367.             return(RETURN_FAIL);
  368.         }
  369.  
  370.         /* Examine the icon's tool types and use the
  371.          * information to fill the startup parameter
  372.          * data structure.
  373.          */
  374.         str = FindToolType(Icon->do_ToolTypes,"DOMAIN");
  375.         if(str == NULL)
  376.             str = FindToolType(Icon->do_ToolTypes,"WORKGROUP");
  377.  
  378.         if(str == NULL)
  379.         {
  380.             if(GetVar("smbfs_domain",env_workgroup_name,sizeof(env_workgroup_name),0) > 0 ||
  381.                GetVar("smbfs_workgroup",env_workgroup_name,sizeof(env_workgroup_name),0) > 0)
  382.             {
  383.                 str = env_workgroup_name;
  384.             }
  385.             else
  386.             {
  387.                 ReportError("Required 'WORKGROUP' parameter was not provided.");
  388.                 Cleanup();
  389.  
  390.                 return(RETURN_ERROR);
  391.             }
  392.         }
  393.  
  394.         args.Workgroup = str;
  395.  
  396.         str = FindToolType(Icon->do_ToolTypes,"USER");
  397.         if(str == NULL)
  398.             str = FindToolType(Icon->do_ToolTypes,"USERNAME");
  399.  
  400.         if(str == NULL)
  401.         {
  402.             if(GetVar("smbfs_user",env_user_name,sizeof(env_user_name),0) > 0 ||
  403.                GetVar("smbfs_username",env_user_name,sizeof(env_user_name),0) > 0)
  404.             {
  405.                 str = env_user_name;
  406.             }
  407.         }
  408.  
  409.         args.UserName = str;
  410.  
  411.         str = FindToolType(Icon->do_ToolTypes,"PASSWORD");
  412.         if(str == NULL)
  413.         {
  414.             if(GetVar("smbfs_password",env_password,sizeof(env_password),0) > 0)
  415.                 str = env_password;
  416.         }
  417.  
  418.         args.Password = str;
  419.  
  420.         if(FindToolType(Icon->do_ToolTypes,"CHANGECASE") != NULL)
  421.             args.ChangeCase = TRUE;
  422.  
  423.         if(FindToolType(Icon->do_ToolTypes,"OMITHIDDEN") != NULL)
  424.             args.OmitHidden = TRUE;
  425.  
  426.         if(FindToolType(Icon->do_ToolTypes,"QUIET") != NULL)
  427.             args.Quiet = TRUE;
  428.  
  429.         if(FindToolType(Icon->do_ToolTypes,"CASE") != NULL ||
  430.            FindToolType(Icon->do_ToolTypes,"CASESENSITIVE") != NULL)
  431.         {
  432.             args.CaseSensitive = TRUE;
  433.         }
  434.  
  435.         str = FindToolType(Icon->do_ToolTypes,"CLIENT");
  436.         if(str == NULL)
  437.             str = FindToolType(Icon->do_ToolTypes,"CLIENTNAME");
  438.  
  439.         args.ClientName = str;
  440.  
  441.         str = FindToolType(Icon->do_ToolTypes,"SERVER");
  442.         if(str == NULL)
  443.             str = FindToolType(Icon->do_ToolTypes,"SERVERNAME");
  444.  
  445.         args.ServerName = str;
  446.  
  447.         str = FindToolType(Icon->do_ToolTypes,"DEVICE");
  448.         if(str == NULL)
  449.             str = FindToolType(Icon->do_ToolTypes,"DEVICENAME");
  450.  
  451.         args.DeviceName = str;
  452.  
  453.         str = FindToolType(Icon->do_ToolTypes,"VOLUME");
  454.         if(str == NULL)
  455.             str = FindToolType(Icon->do_ToolTypes,"VOLUMENAME");
  456.  
  457.         args.VolumeName = str;
  458.  
  459.         str = FindToolType(Icon->do_ToolTypes,"TRANSLATE");
  460.         if(str == NULL)
  461.             str = FindToolType(Icon->do_ToolTypes,"TRANSLATIONFILE");
  462.  
  463.         args.TranslationFile = str;
  464.  
  465.         str = FindToolType(Icon->do_ToolTypes,"SERVICE");
  466.         args.Service = str;
  467.  
  468.         if(str != NULL)
  469.         {
  470.             /* Set up the name of the program, as it will be
  471.              * displayed in error requesters.
  472.              */
  473.             NewProgramName = AllocVec(strlen(WBStartup->sm_ArgList[0].wa_Name) + strlen(" ''") + strlen(str)+1,MEMF_ANY|MEMF_PUBLIC);
  474.             if(NewProgramName != NULL)
  475.                 SPrintf(NewProgramName,"%s '%s'",WBStartup->sm_ArgList[0].wa_Name,str);
  476.         }
  477.  
  478.         str = FindToolType(Icon->do_ToolTypes,"DEBUG");
  479.         if(str == NULL)
  480.             str = FindToolType(Icon->do_ToolTypes,"DEBUGLEVEL");
  481.  
  482.         if(str != NULL)
  483.         {
  484.             if(StrToLong(str,&number) == -1)
  485.             {
  486.                 ReportError("Invalid number '%s' for 'DEBUG' parameter.",str);
  487.                 Cleanup();
  488.  
  489.                 return(RETURN_ERROR);
  490.             }
  491.  
  492.             args.DebugLevel = &number;
  493.         }
  494.  
  495.         str = FindToolType(Icon->do_ToolTypes,"CACHE");
  496.         if(str == NULL)
  497.             str = FindToolType(Icon->do_ToolTypes,"CACHESIZE");
  498.  
  499.         if(str != NULL)
  500.         {
  501.             LONG number;
  502.  
  503.             if(StrToLong(str,&number) == -1)
  504.             {
  505.                 ReportError("Invalid number '%s' for 'CACHE' parameter.",str);
  506.                 Cleanup();
  507.  
  508.                 return(RETURN_ERROR);
  509.             }
  510.  
  511.             cache_size = number;
  512.         }
  513.  
  514.         if(args.Workgroup == NULL)
  515.         {
  516.             ReportError("Required 'WORKGROUP' parameter was not provided.");
  517.             Cleanup();
  518.  
  519.             return(RETURN_ERROR);
  520.         }
  521.  
  522.         if(args.Service == NULL)
  523.         {
  524.             ReportError("'SERVICE' parameter needs an argument.");
  525.             Cleanup();
  526.  
  527.             return(RETURN_ERROR);
  528.         }
  529.     }
  530.     else
  531.     {
  532.         GetProgramName(program_name,sizeof(program_name));
  533.  
  534.         Parameters = ReadArgs(cmd_template,(LONG *)&args,NULL);
  535.         if(Parameters == NULL)
  536.         {
  537.             PrintFault(IoErr(),FilePart(program_name));
  538.             Cleanup();
  539.  
  540.             return(RETURN_ERROR);
  541.         }
  542.  
  543.         if(args.Workgroup == NULL)
  544.         {
  545.             if(GetVar("smbfs_domain",env_workgroup_name,sizeof(env_workgroup_name),0) > 0 ||
  546.                GetVar("smbfs_workgroup",env_workgroup_name,sizeof(env_workgroup_name),0) > 0)
  547.             {
  548.                 args.Workgroup = env_workgroup_name;
  549.             }
  550.             else
  551.             {
  552.                 ReportError("Required 'WORKGROUP' parameter was not provided.");
  553.                 Cleanup();
  554.  
  555.                 return(RETURN_ERROR);
  556.             }
  557.         }
  558.  
  559.         if(args.UserName == NULL)
  560.         {
  561.             if(GetVar("smbfs_user",env_user_name,sizeof(env_user_name),0) > 0 ||
  562.                GetVar("smbfs_username",env_user_name,sizeof(env_user_name),0) > 0)
  563.             {
  564.                 args.UserName = env_user_name;
  565.             }
  566.         }
  567.  
  568.         if(args.Password == NULL)
  569.         {
  570.             if(GetVar("smbfs_password",env_password,sizeof(env_password),0) > 0)
  571.                 args.Password = env_password;
  572.         }
  573.  
  574.         if(args.Service != NULL)
  575.         {
  576.             STRPTR name = FilePart(program_name);
  577.  
  578.             /* Set up the name of the program, as it will be
  579.              * displayed in the proces status list.
  580.              */
  581.             NewProgramName = AllocVec(strlen(name) + strlen(" ''") + strlen(args.Service)+1,MEMF_ANY|MEMF_PUBLIC);
  582.             if(NewProgramName != NULL)
  583.                 SPrintf(NewProgramName,"%s '%s'",name,args.Service);
  584.         }
  585.  
  586.         if(args.CacheSize != NULL)
  587.             cache_size = (*args.CacheSize);
  588.     }
  589.  
  590.     /* Use the default if no user name is given. */
  591.     if(args.UserName == NULL)
  592.         args.UserName = "GUEST";
  593.  
  594.     /* Use the default if no device or volume name is given. */
  595.     if(args.DeviceName == NULL && args.VolumeName == NULL)
  596.         args.DeviceName = "SMBFS";
  597.  
  598.     CaseSensitive = (BOOL)args.CaseSensitive;
  599.     OmitHidden = (BOOL)args.OmitHidden;
  600.  
  601.     /* Configure the debugging options. */
  602.     SETPROGRAMNAME(FilePart(program_name));
  603.  
  604.     if(args.DebugLevel != NULL)
  605.         SETDEBUGLEVEL(*args.DebugLevel);
  606.     else
  607.         SETDEBUGLEVEL(0);
  608.  
  609.     D(("%s (%s)",VERS,DATE));
  610.  
  611.     if(Setup(
  612.         FilePart(program_name),
  613.         args.Service,
  614.         args.Workgroup,
  615.         args.UserName,
  616.         args.Password,
  617.         args.ChangeCase,
  618.         args.ClientName,
  619.         args.ServerName,
  620.         cache_size,
  621.         args.DeviceName,
  622.         args.VolumeName,
  623.         args.TranslationFile))
  624.     {
  625.         Quiet = args.Quiet;
  626.  
  627.         if(Locale != NULL)
  628.             SHOWVALUE(Locale->loc_GMTOffset);
  629.  
  630.         HandleFileSystem(args.DeviceName,args.VolumeName,args.Service);
  631.  
  632.         result = RETURN_WARN;
  633.     }
  634.     else
  635.     {
  636.         result = RETURN_ERROR;
  637.     }
  638.  
  639.     Cleanup();
  640.     return(result);
  641. }
  642.  
  643. /****************************************************************************/
  644.  
  645. /* Obtain the descriptive text corresponding to an error number
  646.  * that may have been generated by the TCP/IP stack.
  647.  */
  648. STRPTR
  649. amitcp_strerror(int error)
  650. {
  651.     struct TagItem tags[2];
  652.     STRPTR result;
  653.  
  654.     ENTER();
  655.  
  656.     tags[0].ti_Tag    = SBTM_GETVAL(SBTC_ERRNOSTRPTR);
  657.     tags[0].ti_Data    = error;
  658.     tags[1].ti_Tag    = TAG_END;
  659.  
  660.     SocketBaseTagList(tags);
  661.  
  662.     result = (STRPTR)tags[0].ti_Data;
  663.  
  664.     RETURN(result);
  665.     return(result);
  666. }
  667.  
  668. /****************************************************************************/
  669.  
  670. /* Return the descriptive text associated with a host lookup failure code. */
  671. STRPTR
  672. host_strerror(int error)
  673. {
  674.     struct TagItem tags[2];
  675.     STRPTR result;
  676.  
  677.     ENTER();
  678.  
  679.     tags[0].ti_Tag    = SBTM_GETVAL(SBTC_HERRNOSTRPTR);
  680.     tags[0].ti_Data    = error;
  681.     tags[1].ti_Tag    = TAG_END;
  682.  
  683.     SocketBaseTagList(tags);
  684.  
  685.     result = (STRPTR)tags[0].ti_Data;
  686.  
  687.     RETURN(result);
  688.     return(result);
  689. }
  690.  
  691. /****************************************************************************/
  692.  
  693. /* Compare two strings, either case sensitive or not
  694.  * sensitive to the case of the letters. How this is
  695.  * to be done is controlled by a global option. This
  696.  * routine is called whenever two SMB file names are
  697.  * to be compared.
  698.  */
  699. LONG
  700. CompareNames(STRPTR a,STRPTR b)
  701. {
  702.     LONG result;
  703.  
  704.     if(CaseSensitive)
  705.         result = strcmp(a,b);
  706.     else
  707.         result = Stricmp(a,b);
  708.  
  709.     return(result);
  710. }
  711.  
  712. /****************************************************************************/
  713.  
  714. /* Translate a string into all upper case characters. */
  715. VOID
  716. StringToUpper(STRPTR s)
  717. {
  718.     UBYTE c;
  719.  
  720.     while((c = (*s)) != '\0')
  721.         (*s++) = ToUpper(c);
  722. }
  723.  
  724. /****************************************************************************/
  725.  
  726. /* Prepare the accumulated list of error messages for display
  727.  * and purge the contents of that list.
  728.  */
  729. STATIC VOID
  730. DisplayErrorList(VOID)
  731. {
  732.     struct MinNode * last = NULL;
  733.     struct MinNode * mn;
  734.     STRPTR str = NULL;
  735.     STRPTR msg;
  736.     LONG len;
  737.  
  738.     /* Determine how much memory will have to be
  739.      * allocated to hold all the accumulated
  740.      * error messages.
  741.      */
  742.     len = 0;
  743.  
  744.     for(mn = ErrorList.mlh_Head ;
  745.         mn->mln_Succ != NULL ;
  746.         mn = mn->mln_Succ)
  747.     {
  748.         last = mn;
  749.  
  750.         msg = (STRPTR)(mn + 1);
  751.  
  752.         len += strlen(msg)+1;
  753.     }
  754.  
  755.     /* Allocate the memory for the messages, then
  756.      * copy them there.
  757.      */
  758.     if(len > 0)
  759.     {
  760.         str = AllocVec(len,MEMF_ANY);
  761.         if(str != NULL)
  762.         {
  763.             str[0] = '\0';
  764.  
  765.             for(mn = ErrorList.mlh_Head ;
  766.                 mn->mln_Succ != NULL ;
  767.                 mn = mn->mln_Succ)
  768.             {
  769.                 msg = (STRPTR)(mn + 1);
  770.  
  771.                 strcat(str,msg);
  772.                 if(mn != last)
  773.                     strcat(str,"\n");
  774.             }
  775.         }
  776.     }
  777.  
  778.     /* Purge the list. */
  779.     while((mn = (struct MinNode *)RemHead((struct List *)&ErrorList)) != NULL)
  780.         FreeVec(mn);
  781.  
  782.     /* Display the error messages. */
  783.     if(str != NULL)
  784.     {
  785.         struct Library * IntuitionBase;
  786.  
  787.         IntuitionBase = OpenLibrary("intuition.library",37);
  788.         if(IntuitionBase != NULL)
  789.         {
  790.             struct EasyStruct es;
  791.             STRPTR title;
  792.  
  793.             memset(&es,0,sizeof(es));
  794.  
  795.             if(NewProgramName == NULL)
  796.                 title = WBStartup->sm_ArgList[0].wa_Name;
  797.             else
  798.                 title = NewProgramName;
  799.  
  800.             es.es_StructSize    = sizeof(es);
  801.             es.es_Title            = title;
  802.             es.es_TextFormat    = str;
  803.             es.es_GadgetFormat    = "Ok";
  804.  
  805.             EasyRequestArgs(NULL,&es,NULL,NULL);
  806.  
  807.             CloseLibrary(IntuitionBase);
  808.         }
  809.  
  810.         FreeVec(str);
  811.     }
  812. }
  813.  
  814. /* Add another error message to the list; the messages are
  815.  * collected so that they may be displayed together when
  816.  * necessary.
  817.  */
  818. STATIC VOID
  819. AddError(STRPTR fmt,va_list args)
  820. {
  821.     LONG len;
  822.  
  823.     len = CVSPrintf(fmt,args);
  824.     if(len > 0)
  825.     {
  826.         struct MinNode * mn;
  827.  
  828.         mn = AllocVec(sizeof(*mn) + len,MEMF_ANY|MEMF_PUBLIC);
  829.         if(mn != NULL)
  830.         {
  831.             STRPTR msg = (STRPTR)(mn + 1);
  832.  
  833.             VSPrintf(msg,fmt,args);
  834.  
  835.             AddTail((struct List *)&ErrorList,(struct Node *)mn);
  836.         }
  837.     }
  838. }
  839.  
  840. /****************************************************************************/
  841.  
  842. /* Report an error that has occured; if the program was not launched
  843.  * from Shell, error messages will be accumulated for later display.
  844.  */
  845. VOID
  846. ReportError(STRPTR fmt,...)
  847. {
  848.     if(NOT Quiet)
  849.     {
  850.         va_list args;
  851.  
  852.         if(WBStartup != NULL)
  853.         {
  854.             va_start(args,fmt);
  855.             AddError(fmt,args);
  856.             va_end(args);
  857.         }
  858.         else
  859.         {
  860.             UBYTE program_name[MAX_FILENAME_LEN];
  861.  
  862.             GetProgramName(program_name,sizeof(program_name));
  863.  
  864.             Printf("%s: ",FilePart(program_name));
  865.  
  866.             va_start(args,fmt);
  867.             VPrintf(fmt,args);
  868.             va_end(args);
  869.  
  870.             Printf("\n");
  871.         }
  872.     }
  873. }
  874.  
  875. /****************************************************************************/
  876.  
  877. /* Release memory allocated from the global pool. */
  878. VOID
  879. FreeVecPooled(APTR address)
  880. {
  881.     if(address != NULL)
  882.     {
  883.         ULONG * mem = address;
  884.  
  885.         #if DEBUG
  886.         {
  887.             if(GETDEBUGLEVEL() > 0)
  888.                 memset(address,0xA3,mem[-1] - sizeof(*mem));
  889.         }
  890.         #endif /* DEBUG */
  891.  
  892.         AsmFreePooled(MemoryPool,&mem[-1],mem[-1],SysBase);
  893.     }
  894. }
  895.  
  896. /* Allocate memory from the global pool. */
  897. APTR
  898. AllocVecPooled(ULONG size)
  899. {
  900.     APTR result = NULL;
  901.  
  902.     if(size > 0)
  903.     {
  904.         ULONG * mem;
  905.  
  906.         size = (sizeof(*mem) + size + 7) & ~7;
  907.  
  908.         mem = AsmAllocPooled(MemoryPool,size,SysBase);
  909.         if(mem != NULL)
  910.         {
  911.             (*mem++) = size;
  912.  
  913.             #if DEBUG
  914.             {
  915.                 if(GETDEBUGLEVEL() > 0)
  916.                     memset(mem,0xA5,mem[-1] - sizeof(*mem));
  917.             }
  918.             #endif /* DEBUG */
  919.  
  920.             result = mem;
  921.         }
  922.     }
  923.  
  924.     return(result);
  925. }
  926.  
  927. /****************************************************************************/
  928.  
  929. /* Obtain the number of seconds to add to the current time
  930.  * to translate local time into UTC.
  931.  */
  932. LONG
  933. GetTimeZoneDelta(VOID)
  934. {
  935.     LONG seconds;
  936.  
  937.     if(Locale != NULL)
  938.     {
  939.         /* The GMT offset actually is the number of minutes to add to
  940.          * the local time to yield Greenwich Mean Time. It is negative
  941.          * for all time zones east of the Greenwich meridian and
  942.          * positive for all time zones west of it.
  943.          */
  944.         seconds = 60 * Locale->loc_GMTOffset;
  945.     }
  946.     else
  947.     {
  948.         seconds = 0;
  949.     }
  950.  
  951.     return(seconds);
  952. }
  953.  
  954. /****************************************************************************/
  955.  
  956. /* Obtain the current time, in standard Unix format, adjusted for the
  957.  * local time zone.
  958.  */
  959. ULONG
  960. GetCurrentTime(VOID)
  961. {
  962.     struct timeval tv;
  963.     ULONG result;
  964.  
  965.     GetSysTime((APTR)&tv);
  966.  
  967.     result = UNIX_TIME_OFFSET + GetTimeZoneDelta() + tv.tv_secs;
  968.  
  969.     return(result);
  970. }
  971.  
  972. /****************************************************************************/
  973.  
  974. /* Fill in a 'tm' type time specification with time information
  975.  * corresponding to the number of seconds provided. Input is
  976.  * in Unix format.
  977.  */
  978. VOID
  979. LocalTime(time_t seconds,struct tm * tm)
  980. {
  981.     struct ClockData clock;
  982.  
  983.     seconds -= GetTimeZoneDelta();
  984.  
  985.     if(seconds < UNIX_TIME_OFFSET)
  986.         seconds = 0;
  987.     else
  988.         seconds -= UNIX_TIME_OFFSET;
  989.  
  990.     Amiga2Date(seconds,&clock);
  991.  
  992.     memset(tm,0,sizeof(*tm));
  993.  
  994.     tm->tm_sec    = clock.sec;
  995.     tm->tm_min    = clock.min;
  996.     tm->tm_hour    = clock.hour;
  997.     tm->tm_mday    = clock.mday;
  998.     tm->tm_mon    = clock.month - 1;
  999.     tm->tm_year    = clock.year - 1900;
  1000. }
  1001.  
  1002. /* Calculate the number of seconds that have passed since January 1st 1970
  1003.  * based upon the time specification provided. Output is in Unix format.
  1004.  */
  1005. time_t
  1006. MakeTime(const struct tm * const tm)
  1007. {
  1008.     struct ClockData clock;
  1009.     time_t seconds;
  1010.  
  1011.     clock.sec    = tm->tm_sec;
  1012.     clock.min    = tm->tm_min;
  1013.     clock.hour    = tm->tm_hour;
  1014.     clock.mday    = tm->tm_mday;
  1015.     clock.month    = tm->tm_mon + 1;
  1016.     clock.year    = tm->tm_year + 1900;
  1017.  
  1018.     seconds = Date2Amiga(&clock) + UNIX_TIME_OFFSET + GetTimeZoneDelta();
  1019.  
  1020.     return(seconds);
  1021. }
  1022.  
  1023. /****************************************************************************/
  1024.  
  1025. struct FormatContext
  1026. {
  1027.     LONG fc_Size;
  1028. };
  1029.  
  1030. STATIC VOID ASM
  1031. CountChar(REG(a3) struct FormatContext * fc)
  1032. {
  1033.     fc->fc_Size++;
  1034. }
  1035.  
  1036. /* Count the number of characters SPrintf() would put into a string. */
  1037. STATIC LONG
  1038. CVSPrintf(STRPTR format_string,va_list args)
  1039. {
  1040.     struct FormatContext fc;
  1041.  
  1042.     fc.fc_Size = 0;
  1043.  
  1044.     RawDoFmt((STRPTR)format_string,args,(VOID (*)())CountChar,&fc);
  1045.  
  1046.     return(fc.fc_Size);
  1047. }
  1048.  
  1049. /****************************************************************************/
  1050.  
  1051. STATIC VOID
  1052. VSPrintf(STRPTR buffer, STRPTR formatString, va_list args)
  1053. {
  1054.     RawDoFmt(formatString,args,(VOID (*)())"\x16\xC0\x4E\x75",buffer);
  1055. }
  1056.  
  1057. /* Format a string for output. */
  1058. VOID
  1059. SPrintf(STRPTR buffer, STRPTR formatString,...)
  1060. {
  1061.     va_list varArgs;
  1062.  
  1063.     va_start(varArgs,formatString);
  1064.     VSPrintf(buffer,formatString,varArgs);
  1065.     va_end(varArgs);
  1066. }
  1067.  
  1068. /****************************************************************************/
  1069.  
  1070. /* NetBIOS broadcast name query code courtesy of Christopher R. Hertel.
  1071.  * Thanks much, Chris!
  1072.  */
  1073. struct addr_entry
  1074. {
  1075.     unsigned short flags;
  1076.     unsigned char address[4];
  1077. };
  1078.  
  1079. struct nmb_header
  1080. {
  1081.     unsigned short name_trn_id;
  1082.     unsigned short flags;
  1083.     unsigned short qdcount;
  1084.     unsigned short ancount;
  1085.     unsigned short nscount;
  1086.     unsigned short arcount;
  1087. };
  1088.  
  1089. static UBYTE *
  1090. L1_Encode(UBYTE * dst, const UBYTE * name, const UBYTE pad, const UBYTE sfx)
  1091. {
  1092.     int i = 0;
  1093.     int j = 0;
  1094.     int k;
  1095.  
  1096.     while(('\0' != name[i]) && (i < 15))
  1097.     {
  1098.         k = ToUpper(name[i]);
  1099.         i++;
  1100.         dst[j++] = 'A' + ((k & 0xF0) >> 4);
  1101.         dst[j++] = 'A' + (k & 0x0F);
  1102.     }
  1103.  
  1104.     i = 'A' + ((pad & 0xF0) >> 4);
  1105.     k = 'A' + (pad & 0x0F);
  1106.  
  1107.     while(j < 30)
  1108.     {
  1109.         dst[j++] = i;
  1110.         dst[j++] = k;
  1111.     }
  1112.  
  1113.     dst[30] = 'A' + ((sfx & 0xF0) >> 4);
  1114.     dst[31] = 'A' + (sfx & 0x0F);
  1115.     dst[32] = '\0';
  1116.  
  1117.     return(dst);
  1118. }
  1119.  
  1120. static int
  1121. L2_Encode(UBYTE * dst, const UBYTE * name, const UBYTE pad, const UBYTE sfx, const UBYTE * scope)
  1122. {
  1123.     int lenpos;
  1124.     int i;
  1125.     int j;
  1126.  
  1127.     if(NULL == L1_Encode(&dst[1], name, pad, sfx))
  1128.         return(-1);
  1129.  
  1130.     dst[0] = 0x20;
  1131.     lenpos = 33;
  1132.  
  1133.     if('\0' != (*scope))
  1134.     {
  1135.         do
  1136.         {
  1137.             for(i = 0, j = (lenpos + 1);
  1138.                 ('.' != scope[i]) && ('\0' != scope[i]);
  1139.                 i++, j++)
  1140.             {
  1141.                 dst[j] = ToUpper(scope[i]);
  1142.             }
  1143.  
  1144.             dst[lenpos] = (UBYTE)i;
  1145.             lenpos += i + 1;
  1146.             scope += i;
  1147.         }
  1148.         while('.' == (*scope++));
  1149.  
  1150.         dst[lenpos] = '\0';
  1151.     }
  1152.  
  1153.     return(lenpos + 1);
  1154. }
  1155.  
  1156. int
  1157. BroadcastNameQuery(char *name, char *scope, UBYTE *address)
  1158. {
  1159.     static const UBYTE header[12] =
  1160.     {
  1161.         0x07, 0xB0,    /* 1964 == 0x07B0. */
  1162.         0x01, 0x10,    /* Binary 0 0000 0010001 0000 */
  1163.         0x00, 0x01,    /* One name query. */
  1164.         0x00, 0x00,    /* Zero answers. */
  1165.         0x00, 0x00,    /* Zero authorities. */
  1166.         0x00, 0x00    /* Zero additional. */
  1167.     };
  1168.  
  1169.     static const UBYTE query_tail[4] =
  1170.     {
  1171.         0x00, 0x20,
  1172.         0x00, 0x01
  1173.     };
  1174.  
  1175.     struct timeval tv;
  1176.     fd_set read_fds;
  1177.     int sock_fd;
  1178.     int option_true = 1;
  1179.     struct sockaddr_in sox;
  1180.     struct nmb_header nmb_header;
  1181.     UBYTE buffer[512];
  1182.     int total_len;
  1183.     int i,n;
  1184.     int result;
  1185.  
  1186.     ENTER();
  1187.  
  1188.     sock_fd = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP);
  1189.     if(sock_fd < 0)
  1190.     {
  1191.         SHOWMSG("couldn't get the socket");
  1192.         result = (-errno);
  1193.         goto out;
  1194.     }
  1195.  
  1196.     if(setsockopt(sock_fd, SOL_SOCKET, SO_BROADCAST, &option_true, sizeof(option_true)) < 0)
  1197.     {
  1198.         SHOWMSG("couldn't enable the broadcast option");
  1199.         result = (-errno);
  1200.         goto out;
  1201.     }
  1202.  
  1203.     sox.sin_family = AF_INET;
  1204.     sox.sin_port = htons(137);
  1205.     sox.sin_addr.s_addr = htonl(0xFFFFFFFF);
  1206.  
  1207.     memcpy(buffer, header, (total_len = sizeof(header)));
  1208.  
  1209.     n = L2_Encode(&buffer[total_len], name, ' ', '\0', scope);
  1210.     if(n < 0)
  1211.     {
  1212.         SHOWMSG("name encoding failed");
  1213.         result = (-EINVAL);
  1214.         goto out;
  1215.     }
  1216.  
  1217.     total_len += n;
  1218.     memcpy(&buffer[total_len], query_tail, sizeof(query_tail));
  1219.     total_len += sizeof(query_tail);
  1220.  
  1221.     result = (-ENOENT);
  1222.     n = 0;
  1223.  
  1224.     /* Send the query packet; retry five times with a one second
  1225.      * delay in between.
  1226.      */
  1227.     for(i = 0 ; i < 5 ; i++)
  1228.     {
  1229.         if(sendto(sock_fd, (void *) buffer, total_len, 0, (struct sockaddr *)&sox, sizeof(struct sockaddr_in)) < 0)
  1230.         {
  1231.             SHOWMSG("could not send the packet");
  1232.             result = (-errno);
  1233.             goto out;
  1234.         }
  1235.  
  1236.         /* Wait for a response to arrive. */
  1237.         tv.tv_secs = 1;
  1238.         tv.tv_micro = 0;
  1239.  
  1240.         FD_ZERO(&read_fds);
  1241.         FD_SET(sock_fd,&read_fds);
  1242.  
  1243.         if(WaitSelect(sock_fd+1, &read_fds, NULL, NULL, &tv, NULL) > 0)
  1244.         {
  1245.             n = recvfrom(sock_fd, buffer, sizeof(buffer), 0, NULL, NULL);
  1246.             if(n < 0)
  1247.             {
  1248.                 SHOWMSG("could not pick up the response packet");
  1249.                 result = (-errno);
  1250.                 goto out;
  1251.             }
  1252.             else if (n > 0)
  1253.             {
  1254.                 break;
  1255.             }
  1256.         }
  1257.     }
  1258.  
  1259.     /* Did we get anything at all? */
  1260.     if(n > sizeof(nmb_header))
  1261.     {
  1262.         /* Check whether the query was successful. */
  1263.         memcpy(&nmb_header, buffer, sizeof(nmb_header));
  1264.         if((nmb_header.flags & 0xF) == OK)
  1265.         {
  1266.             /* Find the NB/IP fields which directly follow
  1267.              * the name.
  1268.              */
  1269.             for(i = sizeof(header) + strlen(&buffer[sizeof(header)])+1 ; i < n - sizeof(query_tail) ; i++)
  1270.             {
  1271.                 if(memcmp(&buffer[i], query_tail, sizeof(query_tail)) == SAME)
  1272.                 {
  1273.                     int start;
  1274.  
  1275.                     /* This should be the start of the interesting bits;
  1276.                      * we skip the NB/IP fields and the TTL field.
  1277.                      */
  1278.                     start = i + sizeof(query_tail) + sizeof(long);
  1279.                     if(start < n)
  1280.                     {
  1281.                         unsigned short read_len;
  1282.                         struct addr_entry addr_entry;
  1283.  
  1284.                         /* This should be the read length. */
  1285.                         memcpy(&read_len, &buffer[start], 2);
  1286.  
  1287.                         /* Is there any useful and readable data attached? */
  1288.                         if(read_len >= sizeof(addr_entry) &&
  1289.                            start + sizeof(read_len) + sizeof(addr_entry) <= n)
  1290.                         {
  1291.                             /* Copy a single address entry; this should be
  1292.                              * just the one we need.
  1293.                              */
  1294.                             memcpy(&addr_entry, &buffer[start + sizeof(read_len)], sizeof(addr_entry));
  1295.  
  1296.                             /* Copy the address field (IPv4 only). */
  1297.                             memcpy(address, addr_entry.address, 4);
  1298.  
  1299.                             result = 0;
  1300.                         }
  1301.                     }
  1302.  
  1303.                     break;
  1304.                 }
  1305.             }
  1306.         }
  1307.     }
  1308.  
  1309. out:
  1310.  
  1311.     if(sock_fd >= 0)
  1312.         CloseSocket(sock_fd);
  1313.  
  1314.     RETURN(result);
  1315.     return(result);
  1316. }
  1317.  
  1318. /****************************************************************************/
  1319.  
  1320. /* Send a disk change notification message which will be picked up
  1321.  * by all applications that listen for this kind of event, e.g.
  1322.  * Workbench.
  1323.  */
  1324. STATIC VOID
  1325. SendDiskChange(ULONG class)
  1326. {
  1327.     struct IOStdReq * input_request = NULL;
  1328.     struct MsgPort * input_port;
  1329.     struct InputEvent ie;
  1330.  
  1331.     ENTER();
  1332.  
  1333.     input_port = CreateMsgPort();
  1334.     if(input_port == NULL)
  1335.         goto out;
  1336.  
  1337.     input_request = CreateIORequest(input_port,sizeof(*input_request));
  1338.     if(input_request == NULL)
  1339.         goto out;
  1340.  
  1341.     if(OpenDevice("input.device",0,(struct IORequest *)input_request,0) != OK)
  1342.         goto out;
  1343.  
  1344.     memset(&ie,0,sizeof(ie));
  1345.  
  1346.     ie.ie_Class        = class;
  1347.     ie.ie_Qualifier    = IEQUALIFIER_MULTIBROADCAST;
  1348.     GetSysTime(&ie.ie_TimeStamp);
  1349.  
  1350.     input_request->io_Command    = IND_WRITEEVENT;
  1351.     input_request->io_Data        = &ie;
  1352.     input_request->io_Length    = sizeof(ie);
  1353.  
  1354.     DoIO((struct IORequest *)input_request);
  1355.  
  1356.  out:
  1357.  
  1358.     if(input_request != NULL)
  1359.     {
  1360.         if(input_request->io_Device != NULL)
  1361.             CloseDevice((struct IORequest *)input_request);
  1362.  
  1363.         DeleteIORequest((struct IORequest *)input_request);
  1364.     }
  1365.  
  1366.     DeleteMsgPort(input_port);
  1367.  
  1368.     LEAVE();
  1369. }
  1370.  
  1371. /****************************************************************************/
  1372.  
  1373. /* Find the file node corresponding to a given name,
  1374.  * skipping a particular entry if necessary.
  1375.  */
  1376. STATIC struct FileNode *
  1377. FindFileNode(STRPTR name,struct FileNode * skip)
  1378. {
  1379.     struct FileNode * result = NULL;
  1380.     struct FileNode * fn;
  1381.  
  1382.     for(fn = (struct FileNode *)FileList.mlh_Head ;
  1383.         fn->fn_MinNode.mln_Succ != NULL ;
  1384.         fn = (struct FileNode *)fn->fn_MinNode.mln_Succ)
  1385.     {
  1386.         if(fn != skip && CompareNames(name,fn->fn_FullName) == SAME)
  1387.         {
  1388.             result = fn;
  1389.             break;
  1390.         }
  1391.     }
  1392.  
  1393.     return(result);
  1394. }
  1395.  
  1396. /* Find the lock node corresponding to a given name,
  1397.  * skipping a particular entry if necessary.
  1398.  */
  1399. STATIC struct LockNode *
  1400. FindLockNode(STRPTR name,struct LockNode * skip)
  1401. {
  1402.     struct LockNode * result = NULL;
  1403.     struct LockNode * ln;
  1404.  
  1405.     for(ln = (struct LockNode *)LockList.mlh_Head ;
  1406.         ln->ln_MinNode.mln_Succ != NULL ;
  1407.         ln = (struct LockNode *)ln->ln_MinNode.mln_Succ)
  1408.     {
  1409.         if(ln != skip && CompareNames(name,ln->ln_FullName) == SAME)
  1410.         {
  1411.             result = ln;
  1412.             break;
  1413.         }
  1414.     }
  1415.  
  1416.     return(result);
  1417. }
  1418.  
  1419. /* Check whether a new reference to be made to a named
  1420.  * file will cause a conflict of access modes. No two
  1421.  * files and locks may refer to the same object if
  1422.  * either of these references is made in exclusive
  1423.  * mode. This is the case which this function is
  1424.  * trying to avoid.
  1425.  */
  1426. STATIC LONG
  1427. CheckAccessModeCollision(STRPTR name,LONG mode)
  1428. {
  1429.     struct LockNode * ln;
  1430.     struct FileNode * fn;
  1431.     LONG error = OK;
  1432.  
  1433.     ENTER();
  1434.     SHOWSTRING(name);
  1435.  
  1436.     fn = FindFileNode(name,NULL);
  1437.     if(fn != NULL)
  1438.     {
  1439.         if(mode != SHARED_LOCK || fn->fn_Mode != SHARED_LOCK)
  1440.         {
  1441.             D(("collides with '%s'",fn->fn_FullName));
  1442.             error = ERROR_OBJECT_IN_USE;
  1443.             goto out;
  1444.         }
  1445.     }
  1446.  
  1447.     ln = FindLockNode(name,NULL);
  1448.     if(ln != NULL)
  1449.     {
  1450.         if(mode != SHARED_LOCK || ln->ln_FileLock.fl_Access != SHARED_LOCK)
  1451.         {
  1452.             D(("collides with '%s'",ln->ln_FullName));
  1453.             error = ERROR_OBJECT_IN_USE;
  1454.             goto out;
  1455.         }
  1456.     }
  1457.  
  1458.  out:
  1459.  
  1460.     RETURN(error);
  1461.     return(error);
  1462. }
  1463.  
  1464. /* Find out whether there already exists a reference to a
  1465.  * certain file or directory.
  1466.  */
  1467. STATIC LONG
  1468. NameAlreadyInUse(STRPTR name)
  1469. {
  1470.     LONG error = OK;
  1471.  
  1472.     ENTER();
  1473.  
  1474.     if(FindFileNode(name,NULL) != NULL)
  1475.     {
  1476.         error = ERROR_OBJECT_IN_USE;
  1477.         goto out;
  1478.     }
  1479.  
  1480.     if(FindLockNode(name,NULL) != NULL)
  1481.     {
  1482.         error = ERROR_OBJECT_IN_USE;
  1483.         goto out;
  1484.     }
  1485.  
  1486.  out:
  1487.  
  1488.     RETURN(error);
  1489.     return(error);
  1490. }
  1491.  
  1492. /* Check whether an Amiga file name uses special characters which
  1493.  * should be avoided when used with the SMB file sharing protocol.
  1494.  */
  1495. STATIC BOOL
  1496. IsReservedName(STRPTR name)
  1497. {
  1498.     BOOL result = FALSE;
  1499.  
  1500.     /* Disallow "." and "..". */
  1501.     if(name[0] == '.' && (name[1] == '\0' || (name[1] == '.' && name[2] == '\0')))
  1502.     {
  1503.         result = TRUE;
  1504.     }
  1505.     else
  1506.     {
  1507.         UBYTE c;
  1508.  
  1509.         /* Disallow the use of the backslash in file names. */
  1510.         while((c = (*name++)) != '\0')
  1511.         {
  1512.             if(c == SMB_PATH_SEPARATOR)
  1513.             {
  1514.                 result = TRUE;
  1515.                 break;
  1516.             }
  1517.         }
  1518.     }
  1519.  
  1520.     return(result);
  1521. }
  1522.  
  1523. /****************************************************************************/
  1524.  
  1525. /* Convert a POSIX error code into an AmigaDOS error code. */
  1526. STATIC LONG
  1527. MapErrnoToIoErr(int error)
  1528. {
  1529.     /* Not all of these mappings make good sense; bear in mind that
  1530.      * POSIX covers more than a hundred different error codes
  1531.      * whereas with AmigaDOS we're stranded with a measly 48...
  1532.      */
  1533.     STATIC const LONG Map[][2] =
  1534.     {
  1535.         EPERM,                ERROR_OBJECT_NOT_FOUND,        /* Operation not permitted */
  1536.         ENOENT,                ERROR_OBJECT_NOT_FOUND,        /* No such file or directory */
  1537.         ESRCH,                ERROR_OBJECT_NOT_FOUND,        /* No such process */
  1538.         EINTR,                ERROR_BREAK,                /* Interrupted system call */
  1539.         EIO,                ERROR_OBJECT_IN_USE,        /* Input/output error */
  1540.         E2BIG,                ERROR_TOO_MANY_ARGS,        /* Argument list too long */
  1541.         EBADF,                ERROR_INVALID_LOCK,            /* Bad file descriptor */
  1542.         ENOMEM,                ERROR_NO_FREE_STORE,        /* Cannot allocate memory */
  1543.         EACCES,                ERROR_OBJECT_IN_USE,        /* Permission denied */
  1544.         ENOTBLK,            ERROR_OBJECT_WRONG_TYPE,    /* Block device required */
  1545.         EBUSY,                ERROR_OBJECT_IN_USE,        /* Device busy */
  1546.         EEXIST,                ERROR_OBJECT_EXISTS,        /* File exists */
  1547.         EXDEV,                ERROR_NOT_IMPLEMENTED,        /* Cross-device link */
  1548.         ENOTDIR,            ERROR_OBJECT_WRONG_TYPE,    /* Not a directory */
  1549.         EISDIR,                ERROR_OBJECT_WRONG_TYPE,    /* Is a directory */
  1550.         EINVAL,                ERROR_BAD_NUMBER,            /* Invalid argument */
  1551.         EFBIG,                ERROR_DISK_FULL,            /* File too large */
  1552.         ENOSPC,                ERROR_DISK_FULL,            /* No space left on device */
  1553.         ESPIPE,                ERROR_SEEK_ERROR,            /* Illegal seek */
  1554.         EROFS,                ERROR_WRITE_PROTECTED,        /* Read-only file system */
  1555.         EMLINK,                ERROR_TOO_MANY_LEVELS,        /* Too many links */
  1556.         ENOTSOCK,            ERROR_OBJECT_WRONG_TYPE,    /* Socket operation on non-socket */
  1557.         EDESTADDRREQ,        ERROR_REQUIRED_ARG_MISSING,    /* Destination address required */
  1558.         EMSGSIZE,            ERROR_LINE_TOO_LONG,        /* Message too long */
  1559.         EPROTOTYPE,            ERROR_BAD_TEMPLATE,            /* Protocol wrong type for socket */
  1560.         ENOPROTOOPT,        ERROR_NOT_IMPLEMENTED,        /* Protocol not available */
  1561.         EPROTONOSUPPORT,    ERROR_NOT_IMPLEMENTED,        /* Protocol not supported */
  1562.         ESOCKTNOSUPPORT,    ERROR_NOT_IMPLEMENTED,        /* Socket type not supported */
  1563.         EOPNOTSUPP,            ERROR_NOT_IMPLEMENTED,        /* Operation not supported */
  1564.         EPFNOSUPPORT,        ERROR_NOT_IMPLEMENTED,        /* Protocol family not supported */
  1565.         EAFNOSUPPORT,        ERROR_NOT_IMPLEMENTED,        /* Address family not supported by protocol family */
  1566.         EADDRINUSE,            ERROR_OBJECT_IN_USE,        /* Address already in use */
  1567.         EADDRNOTAVAIL,        ERROR_OBJECT_NOT_FOUND,        /* Can't assign requested address */
  1568.         ENETDOWN,            ERROR_OBJECT_NOT_FOUND,        /* Network is down */
  1569.         ENETUNREACH,        ERROR_OBJECT_NOT_FOUND,        /* Network is unreachable */
  1570.         ENETRESET,            ERROR_OBJECT_NOT_FOUND,        /* Network dropped connection on reset */
  1571.         ECONNABORTED,        ERROR_OBJECT_NOT_FOUND,        /* Software caused connection abort */
  1572.         ECONNRESET,            ERROR_OBJECT_NOT_FOUND,        /* Connection reset by peer */
  1573.         ENOBUFS,            ERROR_DISK_FULL,            /* No buffer space available */
  1574.         EISCONN,            ERROR_OBJECT_IN_USE,        /* Socket is already connected */
  1575.         ENOTCONN,            ERROR_OBJECT_WRONG_TYPE,    /* Socket is not connected */
  1576.         ESHUTDOWN,            ERROR_INVALID_LOCK,            /* Can't send after socket shutdown */
  1577.         ECONNREFUSED,        ERROR_OBJECT_IN_USE,        /* Connection refused */
  1578.         ELOOP,                ERROR_TOO_MANY_LEVELS,        /* Too many levels of symbolic links */
  1579.         ENAMETOOLONG,        ERROR_LINE_TOO_LONG,        /* File name too long */
  1580.         EHOSTDOWN,            ERROR_OBJECT_NOT_FOUND,        /* Host is down */
  1581.         EHOSTUNREACH,        ERROR_OBJECT_NOT_FOUND,        /* No route to host */
  1582.         ENOTEMPTY,            ERROR_DIRECTORY_NOT_EMPTY,    /* Directory not empty */
  1583.         EPROCLIM,            ERROR_TASK_TABLE_FULL,        /* Too many processes */
  1584.         EUSERS,                ERROR_TASK_TABLE_FULL,        /* Too many users */
  1585.         EDQUOT,                ERROR_DISK_FULL,            /* Disc quota exceeded */
  1586.         -1
  1587.     };
  1588.  
  1589.     LONG result = ERROR_ACTION_NOT_KNOWN;
  1590.     LONG i;
  1591.  
  1592.     ENTER();
  1593.  
  1594.     if(error < 0)
  1595.         error = (-error);
  1596.  
  1597.     for(i = 0 ; Map[i][0] != -1 ; i++)
  1598.     {
  1599.         if(Map[i][0] == error)
  1600.         {
  1601.             result = Map[i][1];
  1602.             break;
  1603.         }
  1604.     }
  1605.  
  1606.     RETURN(result);
  1607.     return(result);
  1608. }
  1609.  
  1610. /****************************************************************************/
  1611.  
  1612. /* Translate a BCPL style file name (i.e. length is in the first byte)
  1613.  * via a mapping table.
  1614.  */
  1615. STATIC VOID INLINE
  1616. TranslateBName(UBYTE * name,UBYTE * map)
  1617. {
  1618.     if(TranslateNames)
  1619.     {
  1620.         LONG len;
  1621.         UBYTE c;
  1622.  
  1623.         len = (*name++);
  1624.  
  1625.         while(len-- > 0)
  1626.         {
  1627.             c = (*name);
  1628.  
  1629.             (*name++) = map[c];
  1630.         }
  1631.     }
  1632. }
  1633.  
  1634. /* Translate a NUL terminated file name via a mapping table. */
  1635. STATIC VOID INLINE
  1636. TranslateCName(UBYTE * name,UBYTE * map)
  1637. {
  1638.     if(TranslateNames)
  1639.     {
  1640.         UBYTE c;
  1641.  
  1642.         while((c = (*name)) != '\0')
  1643.             (*name++) = map[c];
  1644.     }
  1645. }
  1646.  
  1647. /****************************************************************************/
  1648.  
  1649. /* Remove a DosList entry using the proper protocols. Note that
  1650.  * this function can fail!
  1651.  */
  1652. STATIC BOOL
  1653. ReallyRemoveDosEntry(struct DosList * entry)
  1654. {
  1655.     struct Message * mn;
  1656.     struct MsgPort * port;
  1657.     struct DosList * dl;
  1658.     BOOL result = FALSE;
  1659.     LONG kind,i;
  1660.  
  1661.     if(entry->dol_Type == DLT_DEVICE)
  1662.         kind = LDF_DEVICES;
  1663.     else
  1664.         kind = LDF_VOLUMES;
  1665.  
  1666.     port = entry->dol_Task;
  1667.  
  1668.     for(i = 0 ; i < 100 ; i++)
  1669.     {
  1670.         dl = AttemptLockDosList(LDF_WRITE|kind);
  1671.         if(((ULONG)dl) <= 1)
  1672.             dl = NULL;
  1673.  
  1674.         if(dl != NULL)
  1675.         {
  1676.             RemDosEntry(entry);
  1677.  
  1678.             UnLockDosList(LDF_WRITE|kind);
  1679.  
  1680.             result = TRUE;
  1681.  
  1682.             break;
  1683.         }
  1684.  
  1685.         while((mn = GetMsg(port)) != NULL)
  1686.             ReplyPkt((struct DosPacket *)mn->mn_Node.ln_Name,DOSFALSE,ERROR_ACTION_NOT_KNOWN);
  1687.  
  1688.         Delay(TICKS_PER_SECOND / 10);
  1689.     }
  1690.  
  1691.     return(result);
  1692. }
  1693.  
  1694. /****************************************************************************/
  1695.  
  1696. /* Release all resources allocated by the Setup() routine. */
  1697. STATIC VOID
  1698. Cleanup(VOID)
  1699. {
  1700.     ENTER();
  1701.  
  1702.     /* If any errors have cropped up, display them now before
  1703.      * call it quits.
  1704.      */
  1705.     DisplayErrorList();
  1706.  
  1707.     if(NewProgramName != NULL)
  1708.     {
  1709.         FreeVec(NewProgramName);
  1710.         NewProgramName = NULL;
  1711.     }
  1712.  
  1713.     if(Parameters != NULL)
  1714.     {
  1715.         FreeArgs(Parameters);
  1716.         Parameters = NULL;
  1717.     }
  1718.  
  1719.     if(Icon != NULL)
  1720.     {
  1721.         FreeDiskObject(Icon);
  1722.         Icon = NULL;
  1723.     }
  1724.  
  1725.     if(ServerData != NULL)
  1726.     {
  1727.         smba_disconnect(ServerData);
  1728.         ServerData = NULL;
  1729.     }
  1730.  
  1731.     if(DeviceNode != NULL)
  1732.     {
  1733.         if(DeviceNodeAdded)
  1734.         {
  1735.             if(ReallyRemoveDosEntry(DeviceNode))
  1736.                 FreeDosEntry(DeviceNode);
  1737.         }
  1738.         else
  1739.         {
  1740.             FreeDosEntry(DeviceNode);
  1741.         }
  1742.  
  1743.         DeviceNode = NULL;
  1744.     }
  1745.  
  1746.     if(VolumeNode != NULL)
  1747.     {
  1748.         if(VolumeNodeAdded)
  1749.         {
  1750.             if(ReallyRemoveDosEntry(VolumeNode))
  1751.                 FreeDosEntry(VolumeNode);
  1752.  
  1753.             SendDiskChange(IECLASS_DISKREMOVED);
  1754.         }
  1755.         else
  1756.         {
  1757.             FreeDosEntry(VolumeNode);
  1758.         }
  1759.  
  1760.         VolumeNode = NULL;
  1761.     }
  1762.  
  1763.     if(FileSystemPort != NULL)
  1764.     {
  1765.         struct Message * mn;
  1766.  
  1767.         /* Return all queued packets; there should be none, though. */
  1768.         while((mn = GetMsg(FileSystemPort)) != NULL)
  1769.             ReplyPkt((struct DosPacket *)mn->mn_Node.ln_Name,DOSFALSE,ERROR_ACTION_NOT_KNOWN);
  1770.  
  1771.         DeleteMsgPort(FileSystemPort);
  1772.         FileSystemPort = NULL;
  1773.     }
  1774.  
  1775.     if(TimerBase != NULL)
  1776.     {
  1777.         CloseDevice((struct IORequest *)&TimerRequest);
  1778.         TimerBase = NULL;
  1779.     }
  1780.  
  1781.     if(SocketBase != NULL)
  1782.     {
  1783.         CloseLibrary(SocketBase);
  1784.         SocketBase = NULL;
  1785.     }
  1786.  
  1787.     if(UtilityBase != NULL)
  1788.     {
  1789.         CloseLibrary(UtilityBase);
  1790.         UtilityBase = NULL;
  1791.     }
  1792.  
  1793.     if(IconBase != NULL)
  1794.     {
  1795.         CloseLibrary(IconBase);
  1796.         IconBase = NULL;
  1797.     }
  1798.  
  1799.     if(Locale != NULL)
  1800.     {
  1801.         CloseLocale(Locale);
  1802.         Locale = NULL;
  1803.     }
  1804.  
  1805.     if(LocaleBase != NULL)
  1806.     {
  1807.         CloseLibrary(LocaleBase);
  1808.         LocaleBase = NULL;
  1809.     }
  1810.  
  1811.     if(MemoryPool != NULL)
  1812.     {
  1813.         AsmDeletePool(MemoryPool,SysBase);
  1814.         MemoryPool = NULL;
  1815.     }
  1816.  
  1817.     if(DOSBase != NULL)
  1818.     {
  1819.         CloseLibrary(DOSBase);
  1820.         DOSBase = NULL;
  1821.     }
  1822.  
  1823.     if(WBStartup != NULL)
  1824.     {
  1825.         Forbid();
  1826.         ReplyMsg((struct Message *)WBStartup);
  1827.     }
  1828.  
  1829.     LEAVE();
  1830. }
  1831.  
  1832. /* Allocate all the necessary resources to get going. */
  1833. STATIC BOOL
  1834. Setup(
  1835.     STRPTR    program_name,
  1836.     STRPTR    service,
  1837.     STRPTR    workgroup,
  1838.     STRPTR     username,
  1839.     STRPTR    opt_password,
  1840.     BOOL    opt_changecase,
  1841.     STRPTR    opt_clientname,
  1842.     STRPTR    opt_servername,
  1843.     int        opt_cachesize,
  1844.     STRPTR    device_name,
  1845.     STRPTR    volume_name,
  1846.     STRPTR    translation_file)
  1847. {
  1848.     BOOL result = FALSE;
  1849.     int error;
  1850.     UBYTE name[MAX_FILENAME_LEN];
  1851.     LONG i;
  1852.  
  1853.     ENTER();
  1854.  
  1855.     NewList((struct List *)&FileList);
  1856.     NewList((struct List *)&LockList);
  1857.  
  1858.     MemoryPool = AsmCreatePool(MEMF_ANY|MEMF_PUBLIC,4096,4096,SysBase);
  1859.     if(MemoryPool == NULL)
  1860.     {
  1861.         ReportError("Could not create memory pool.");
  1862.         goto out;
  1863.     }
  1864.  
  1865.     LocaleBase = OpenLibrary("locale.library",38);
  1866.     if(LocaleBase != NULL)
  1867.         Locale = OpenLocale(NULL);
  1868.  
  1869.     memset(&TimerRequest,0,sizeof(TimerRequest));
  1870.  
  1871.     if(OpenDevice(TIMERNAME,UNIT_VBLANK,(struct IORequest *)&TimerRequest,0) != OK)
  1872.     {
  1873.         ReportError("Could not open 'timer.device'.");
  1874.         goto out;
  1875.     }
  1876.  
  1877.     TimerBase = TimerRequest.tr_node.io_Device;
  1878.  
  1879.     SocketBase = OpenLibrary("bsdsocket.library",3);
  1880.     if(SocketBase == NULL)
  1881.     {
  1882.         ReportError("Could not open 'bsdsocket.library' V3; TCP/IP stack not running?");
  1883.         goto out;
  1884.     }
  1885.  
  1886.     error = SocketBaseTags(
  1887.         SBTM_SETVAL(SBTC_ERRNOPTR(sizeof(errno))),    &errno,
  1888.         SBTM_SETVAL(SBTC_HERRNOLONGPTR),            &h_errno,
  1889.         SBTM_SETVAL(SBTC_LOGTAGPTR),                program_name,
  1890.         SBTM_SETVAL(SBTC_BREAKMASK),                SIGBREAKF_CTRL_C,
  1891.     TAG_END);
  1892.     if(error != OK)
  1893.     {
  1894.         ReportError("Could not initialize 'bsdsocket.library' (%ld, %s).",error,amitcp_strerror(error));
  1895.         goto out;
  1896.     }
  1897.  
  1898.     if(opt_changecase)
  1899.     {
  1900.         for(i = 0 ; i < strlen(opt_password) ; i++)
  1901.             opt_password[i] = ToUpper(opt_password[i]);
  1902.     }
  1903.  
  1904.     TranslateNames = FALSE;
  1905.  
  1906.     /* Read the translation file, if possible. */
  1907.     if(translation_file != NULL)
  1908.     {
  1909.         LONG error = OK;
  1910.         STRPTR msg = NULL;
  1911.         BPTR file;
  1912.  
  1913.         file = Open(translation_file,MODE_OLDFILE);
  1914.         if(file != ZERO)
  1915.         {
  1916.             if(Read(file,A2M,256) != 256 ||
  1917.                Read(file,M2A,256) != 256)
  1918.             {
  1919.                 msg = "Could not read translation file";
  1920.                 error = IoErr();
  1921.             }
  1922.  
  1923.             Close(file);
  1924.         }
  1925.         else
  1926.         {
  1927.             msg = "Could not open translation file";
  1928.             error = IoErr();
  1929.         }
  1930.  
  1931.         if(msg == NULL)
  1932.         {
  1933.             TranslateNames = TRUE;
  1934.         }
  1935.         else
  1936.         {
  1937.             UBYTE description[100];
  1938.  
  1939.             Fault(error,NULL,description,sizeof(description));
  1940.             for(i = ((int)strlen(description)) - 1 ; i >= 0 ; i--)
  1941.             {
  1942.                 if(description[i] == '\n')
  1943.                     description[i] = '\0';
  1944.             }
  1945.  
  1946.             ReportError("%s '%s' (%ld, %s).",msg,translation_file,error,description);
  1947.             goto out;
  1948.         }
  1949.     }
  1950.  
  1951.     error = smba_start(service,workgroup,username,opt_password,opt_clientname,opt_servername,opt_cachesize,&ServerData);
  1952.     if(error < 0)
  1953.         goto out;
  1954.  
  1955.     FileSystemPort = CreateMsgPort();
  1956.     if(FileSystemPort == NULL)
  1957.     {
  1958.         ReportError("Could not create filesystem port.");
  1959.         goto out;
  1960.     }
  1961.  
  1962.     Forbid();
  1963.  
  1964.     /* If a device name was provided, check whether it is
  1965.      * well-formed.
  1966.      */
  1967.     if(device_name != NULL)
  1968.     {
  1969.         struct DosList * dl;
  1970.         BOOL device_exists;
  1971.  
  1972.         for(i = 0 ; i < strlen(device_name) ; i++)
  1973.         {
  1974.             if(device_name[i] == '/')
  1975.             {
  1976.                 Permit();
  1977.  
  1978.                 ReportError("Device name '%s' cannot be used with AmigaDOS.",device_name);
  1979.                 goto out;
  1980.             }
  1981.         }
  1982.  
  1983.         if(device_name[0] == '\0')
  1984.         {
  1985.             Permit();
  1986.  
  1987.             ReportError("Device name '%s' cannot be used with AmigaDOS.",device_name);
  1988.             goto out;
  1989.         }
  1990.  
  1991.         strncpy(name,device_name,255);
  1992.         name[255] = '\0';
  1993.  
  1994.         /* Chop off any trailing colons. */
  1995.         for(i = strlen(name)-1 ; i >= 0 ; i--)
  1996.         {
  1997.             if(name[i] == ':')
  1998.                 name[i] = '\0';
  1999.         }
  2000.  
  2001.         if(device_name[0] == '\0')
  2002.         {
  2003.             Permit();
  2004.  
  2005.             ReportError("Device name '%s:' cannot be used with AmigaDOS.",device_name);
  2006.             goto out;
  2007.         }
  2008.  
  2009.         dl = LockDosList(LDF_READ|LDF_DEVICES);
  2010.         device_exists = (BOOL)(FindDosEntry(dl,device_name,LDF_DEVICES) != NULL);
  2011.         UnLockDosList(LDF_DEVICES);
  2012.  
  2013.         if(device_exists)
  2014.         {
  2015.             Permit();
  2016.  
  2017.             ReportError("Device name '%s:' is already taken.",device_name);
  2018.             goto out;
  2019.         }
  2020.     }
  2021.     else
  2022.     {
  2023.         struct DosList * dl;
  2024.         BOOL device_exists;
  2025.  
  2026.         /* Find a unique device name. */
  2027.         for(i = 0 ; i < 100 ; i++)
  2028.         {
  2029.             SPrintf(name,"SMBFS%ld",i);
  2030.  
  2031.             dl = LockDosList(LDF_READ|LDF_DEVICES);
  2032.             device_exists = (BOOL)(FindDosEntry(dl,name,LDF_DEVICES) != NULL);
  2033.             UnLockDosList(LDF_DEVICES);
  2034.  
  2035.             if(NOT device_exists)
  2036.             {
  2037.                 device_name = name;
  2038.                 break;
  2039.             }
  2040.         }
  2041.     }
  2042.  
  2043.     if(device_name != NULL)
  2044.     {
  2045.         DeviceNode = MakeDosEntry(name,DLT_DEVICE);
  2046.         if(DeviceNode == NULL)
  2047.         {
  2048.             Permit();
  2049.  
  2050.             ReportError("Could not create device node.");
  2051.             goto out;
  2052.         }
  2053.  
  2054.         DeviceNode->dol_Task = FileSystemPort;
  2055.  
  2056.         AddDosEntry(DeviceNode);
  2057.         DeviceNodeAdded = TRUE;
  2058.     }
  2059.  
  2060.     Permit();
  2061.  
  2062.     /* Now take care of the volume name; make sure that it is
  2063.      * well-formed.
  2064.      */
  2065.     if(volume_name == NULL)
  2066.         strncpy(name,device_name,255);
  2067.     else
  2068.         strncpy(name,volume_name,255);
  2069.  
  2070.     name[255] = '\0';
  2071.  
  2072.     for(i = 0 ; i < strlen(name) ; i++)
  2073.     {
  2074.         if(name[i] == '/')
  2075.         {
  2076.             ReportError("Volume name '%s' cannot be used with AmigaDOS.",name);
  2077.             goto out;
  2078.         }
  2079.     }
  2080.  
  2081.     if(name[0] == '\0')
  2082.     {
  2083.         ReportError("Volume name '%s' cannot be used with AmigaDOS.",name);
  2084.         goto out;
  2085.     }
  2086.  
  2087.     /* Chop off any trailing colons. */
  2088.     for(i = strlen(name)-1 ; i >= 0 ; i--)
  2089.     {
  2090.         if(name[i] == ':')
  2091.             name[i] = '\0';
  2092.     }
  2093.  
  2094.     VolumeNode = MakeDosEntry(name,DLT_VOLUME);
  2095.     if(VolumeNode == NULL)
  2096.     {
  2097.         ReportError("Could not create volume node.");
  2098.         goto out;
  2099.     }
  2100.  
  2101.     VolumeNode->dol_Task = FileSystemPort;
  2102.     DateStamp(&VolumeNode->dol_misc.dol_volume.dol_VolumeDate);
  2103.     VolumeNode->dol_misc.dol_volume.dol_DiskType = ID_DOS_DISK;
  2104.  
  2105.     if(volume_name != NULL)
  2106.     {
  2107.          AddDosEntry(VolumeNode);
  2108.         VolumeNodeAdded = TRUE;
  2109.  
  2110.         SendDiskChange(IECLASS_DISKINSERTED);
  2111.     }
  2112.  
  2113.     SetProgramName(NewProgramName);
  2114.  
  2115.     result = TRUE;
  2116.  
  2117.  out:
  2118.  
  2119.     RETURN(result);
  2120.     return(result);
  2121. }
  2122.  
  2123. /****************************************************************************/
  2124.  
  2125. /* Convert a BCPL string into a standard NUL terminated 'C' string. */
  2126. STATIC VOID INLINE
  2127. ConvertBString(LONG max_len,STRPTR cstring,APTR bstring)
  2128. {
  2129.     STRPTR from = bstring;
  2130.     LONG len = from[0];
  2131.  
  2132.     if(len > max_len-1)
  2133.         len = max_len-1;
  2134.  
  2135.     if(len > 0)
  2136.         strncpy(cstring,from+1,len);
  2137.  
  2138.     cstring[len] = '\0';
  2139. }
  2140.  
  2141. /* Convert a NUL terminated 'C' string into a BCPL string. */
  2142. STATIC VOID INLINE
  2143. ConvertCString(LONG max_len,APTR bstring,STRPTR cstring)
  2144. {
  2145.     LONG len = strlen(cstring);
  2146.     STRPTR to = bstring;
  2147.  
  2148.     if(len > max_len-1)
  2149.         len = max_len-1;
  2150.  
  2151.     (*to++) = len;
  2152.     memcpy(to,cstring,len);
  2153. }
  2154.  
  2155. /****************************************************************************/
  2156.  
  2157. /* Build the fully qualified name of a file or directory in reference
  2158.  * to the name of the parent directory. This takes care of all the
  2159.  * special cases, such as the root directory. The result will be converted
  2160.  * to be in a form suitable for use with the SMB file sharing service.
  2161.  */
  2162. STATIC LONG
  2163. BuildFullName(
  2164.     STRPTR        parent_name,
  2165.     STRPTR        name,
  2166.     STRPTR *    result_ptr)
  2167. {
  2168.     LONG error = OK;
  2169.     STRPTR buffer;
  2170.     LONG len;
  2171.  
  2172.     ENTER();
  2173.  
  2174.     SHOWSTRING(parent_name);
  2175.     SHOWSTRING(name);
  2176.  
  2177.     (*result_ptr) = NULL;
  2178.  
  2179.     /* parent_name == NULL means 'root directory', and
  2180.      * so does parent_name == "\\".
  2181.      *
  2182.      * name == NULL means 'use parent name', and so
  2183.      * does name == "".
  2184.      */
  2185.  
  2186.     if(name != NULL && name[0] == '\0')
  2187.         name = NULL;
  2188.  
  2189.     /* Relative to root directory? */
  2190.     if(name != NULL && name[0] == ':')
  2191.     {
  2192.         parent_name = NULL;
  2193.  
  2194.         while(name[0] == ':')
  2195.             name++;
  2196.     }
  2197.  
  2198.     if(parent_name != NULL && strcmp(parent_name,SMB_ROOT_DIR_NAME) == SAME)
  2199.         parent_name = NULL;
  2200.  
  2201.     /* Now, how much room is needed for the complete
  2202.      * path to fit into a buffer?
  2203.      */
  2204.     len = 2;
  2205.  
  2206.     if(parent_name != NULL)
  2207.         len += strlen(parent_name) + 1;
  2208.  
  2209.     if(name != NULL)
  2210.         len += strlen(name) + 1;
  2211.  
  2212.     buffer = AllocVecPooled(len+3);
  2213.     if(buffer == NULL)
  2214.     {
  2215.         error = ERROR_NO_FREE_STORE;
  2216.         goto out;
  2217.     }
  2218.  
  2219.     /* The path starts with the name of parent. */
  2220.     if(parent_name != NULL)
  2221.     {
  2222.         if(parent_name[0] == SMB_PATH_SEPARATOR)
  2223.         {
  2224.             while(parent_name[1] == SMB_PATH_SEPARATOR)
  2225.                 parent_name++;
  2226.  
  2227.             strcpy(buffer,parent_name);
  2228.         }
  2229.         else
  2230.         {
  2231.             buffer[0] = SMB_PATH_SEPARATOR;
  2232.             strcpy(&buffer[1],parent_name);
  2233.         }
  2234.     }
  2235.     else
  2236.     {
  2237.         buffer[0] = '\0';
  2238.     }
  2239.  
  2240.     /* If there's a name to add, do just that. */
  2241.     if(name != NULL)
  2242.     {
  2243.         LONG diff,i,j,start;
  2244.  
  2245.         if(buffer[0] == '\0')
  2246.         {
  2247.             buffer[0] = SMB_PATH_SEPARATOR;
  2248.             buffer[1] = '\0';
  2249.         }
  2250.  
  2251.         /* Append the name. */
  2252.         if(parent_name != NULL)
  2253.         {
  2254.             for(i = 0 ; i < strlen(buffer) ; i++)
  2255.             {
  2256.                 if(buffer[i] == SMB_PATH_SEPARATOR)
  2257.                     buffer[i] = '/';
  2258.             }
  2259.  
  2260.             AddPart(buffer,name,len);
  2261.         }
  2262.         else
  2263.         {
  2264.             strcat(buffer,name);
  2265.         }
  2266.  
  2267.         /* Parse the path specification, eliminating // combinations. */
  2268.         len = strlen(buffer);
  2269.  
  2270.         i = len;
  2271.         while(len > 1)
  2272.         {
  2273.             if((buffer[len-1] == '/') && (buffer[len-2] != '/') && (buffer[len-2] != ':'))
  2274.                 buffer[--len] = '\0';
  2275.  
  2276.             i--;
  2277.             if((i == 0) || (buffer[i] == ':') || (buffer[i-1] == ':'))
  2278.                 break;
  2279.  
  2280.             if((i > 1) && (buffer[i] == '/') && (buffer[i-1] == '/') && (buffer[i-2] != ':') && (buffer[i-2] != '/'))
  2281.             {
  2282.                 start = i;
  2283.                 i -= 2;
  2284.  
  2285.                 while((i > 0) && (buffer[i] != ':') && (buffer[i] != '/'))
  2286.                     i--;
  2287.  
  2288.                 if((buffer[i] == ':') || (buffer[i] == '/'))
  2289.                     i++;
  2290.  
  2291.                 j = i;
  2292.                 diff = start-i+1;
  2293.                 len -= diff;
  2294.  
  2295.                 while(j < len)
  2296.                 {
  2297.                     buffer[j] = buffer[j+diff];
  2298.                     j++;
  2299.                 }
  2300.  
  2301.                 buffer[len] = '\0';
  2302.                 i = len;
  2303.             }
  2304.         }
  2305.  
  2306.         /* Last sanity check; there shouldn't be any isolated
  2307.          * backslashes and no double backslashes should remain
  2308.          * either.
  2309.          */
  2310.         len = strlen(buffer);
  2311.         if(len > 0)
  2312.         {
  2313.             LONG start;
  2314.  
  2315.             if(buffer[len-1] == '/')
  2316.             {
  2317.                 error = ERROR_INVALID_COMPONENT_NAME;
  2318.                 goto out;
  2319.             }
  2320.  
  2321.             if(buffer[0] == '/' && buffer[1] == '/')
  2322.             {
  2323.                 for(i = 0 ; i <= len ; i++)
  2324.                     buffer[i] = buffer[i+1];
  2325.  
  2326.                 len--;
  2327.             }
  2328.  
  2329.             for(i = 0 ; i < len-1 ; i++)
  2330.             {
  2331.                 if(buffer[i] == '/' && buffer[i+1] == '/')
  2332.                 {
  2333.                     error = ERROR_INVALID_COMPONENT_NAME;
  2334.                     goto out;
  2335.                 }
  2336.             }
  2337.  
  2338.             start = -1;
  2339.  
  2340.             for(i = 0 ; i < len ; i++)
  2341.             {
  2342.                 if(buffer[i] == ':')
  2343.                     start = i+1;
  2344.             }
  2345.  
  2346.             if(start != -1)
  2347.             {
  2348.                 for(i = 0 ; i <= len - start + 1 ; i++)
  2349.                     buffer[i] = buffer[start+i];
  2350.             }
  2351.  
  2352.             len = strlen(buffer);
  2353.  
  2354.             if(buffer[0] != '/')
  2355.             {
  2356.                 for(i = len+1 ; i > 0 ; i--)
  2357.                     buffer[i] = buffer[i-1];
  2358.  
  2359.                 buffer[0] = '/';
  2360.                 len++;
  2361.             }
  2362.  
  2363.             for(i = 0 ; i < len ; i++)
  2364.             {
  2365.                 if(buffer[i] == '/')
  2366.                     buffer[i] = SMB_PATH_SEPARATOR;
  2367.             }
  2368.         }
  2369.     }
  2370.  
  2371.     /* If the buffer remains empty, it means that the
  2372.      * reference should be made to the root directory.
  2373.      */
  2374.     if(buffer[0] == '\0' || (buffer[0] == SMB_PATH_SEPARATOR && buffer[1] == SMB_PATH_SEPARATOR && buffer[2] == '\0'))
  2375.         strcpy(buffer,SMB_ROOT_DIR_NAME);
  2376.  
  2377.     (*result_ptr) = buffer;
  2378.  
  2379.     SHOWSTRING(buffer);
  2380.  
  2381.  out:
  2382.  
  2383.     if(error != OK)
  2384.         FreeVecPooled(buffer);
  2385.  
  2386.     RETURN(error);
  2387.     return(error);
  2388. }
  2389.  
  2390. /****************************************************************************/
  2391.  
  2392. STATIC BPTR
  2393. Action_Parent(
  2394.     struct FileLock *    parent,
  2395.     LONG *                error_ptr)
  2396. {
  2397.     BPTR result = ZERO;
  2398.     STRPTR full_name = NULL;
  2399.     STRPTR parent_name;
  2400.     BOOL cleanup = TRUE;
  2401.     struct LockNode * ln = NULL;
  2402.     LONG error;
  2403.     LONG i;
  2404.  
  2405.     ENTER();
  2406.  
  2407.     SHOWVALUE(parent);
  2408.  
  2409.     if(parent != NULL)
  2410.     {
  2411.         struct LockNode * ln = (struct LockNode *)parent->fl_Key;
  2412.  
  2413.         parent_name = ln->ln_FullName;
  2414.         if(strcmp(parent_name,SMB_ROOT_DIR_NAME) == SAME)
  2415.             parent_name = NULL;
  2416.     }
  2417.     else
  2418.     {
  2419.         parent_name = NULL;
  2420.     }
  2421.  
  2422.     error = BuildFullName(parent_name,NULL,&full_name);
  2423.     if(error != OK)
  2424.         goto out;
  2425.  
  2426.     /* Now for the interesting bit. Is this already the
  2427.      * root directory we're dealing with?
  2428.      */
  2429.     if(strcmp(full_name,SMB_ROOT_DIR_NAME) == SAME)
  2430.         goto out;
  2431.  
  2432.     ln = AllocVecPooled(sizeof(*ln));
  2433.     if(ln == NULL)
  2434.     {
  2435.         error = ERROR_NO_FREE_STORE;
  2436.         goto out;
  2437.     }
  2438.  
  2439.     memset(ln,0,sizeof(*ln));
  2440.  
  2441.     ln->ln_FileLock.fl_Key        = (LONG)ln;
  2442.     ln->ln_FileLock.fl_Access    = SHARED_LOCK;
  2443.     ln->ln_FileLock.fl_Task        = FileSystemPort;
  2444.     ln->ln_FileLock.fl_Volume    = MKBADDR(VolumeNode);
  2445.     ln->ln_FullName                = full_name;
  2446.  
  2447.     for(i = strlen(full_name)-1 ; i >= 0 ; i--)
  2448.     {
  2449.         if(i == 0)
  2450.         {
  2451.             strcpy(full_name,SMB_ROOT_DIR_NAME);
  2452.             break;
  2453.         }
  2454.         else if (full_name[i] == SMB_PATH_SEPARATOR)
  2455.         {
  2456.             full_name[i] = '\0';
  2457.             break;
  2458.         }
  2459.     }
  2460.  
  2461.     SHOWSTRING(full_name);
  2462.  
  2463.     error = smba_open(ServerData,full_name,&ln->ln_File);
  2464.     if(error < 0)
  2465.     {
  2466.         error = MapErrnoToIoErr(error);
  2467.         goto out;
  2468.     }
  2469.  
  2470.     AddTail((struct List *)&LockList,(struct Node *)ln);
  2471.     result = MKBADDR(&ln->ln_FileLock);
  2472.     cleanup = FALSE;
  2473.     SHOWVALUE(&ln->ln_FileLock);
  2474.  
  2475.  out:
  2476.  
  2477.     if(cleanup)
  2478.     {
  2479.         FreeVecPooled(full_name);
  2480.         FreeVecPooled(ln);
  2481.     }
  2482.  
  2483.     (*error_ptr) = error;
  2484.  
  2485.     RETURN(result);
  2486.     return(result);
  2487. }
  2488.  
  2489. /****************************************************************************/
  2490.  
  2491. STATIC LONG
  2492. Action_DeleteObject(
  2493.     struct FileLock *    parent,
  2494.     APTR                bcpl_name,
  2495.     LONG *                error_ptr)
  2496. {
  2497.     LONG result = DOSFALSE;
  2498.     STRPTR full_name = NULL;
  2499.     smba_file_t * file = NULL;
  2500.     STRPTR parent_name;
  2501.     STRPTR full_parent_name = NULL;
  2502.     UBYTE name[MAX_FILENAME_LEN];
  2503.     struct LockNode * ln;
  2504.     smba_stat_t stat;
  2505.     LONG error;
  2506.     int i;
  2507.  
  2508.     ENTER();
  2509.  
  2510.     if(WriteProtected)
  2511.     {
  2512.         error = ERROR_DISK_WRITE_PROTECTED;
  2513.         goto out;
  2514.     }
  2515.  
  2516.     SHOWVALUE(parent);
  2517.  
  2518.     if(parent != NULL)
  2519.     {
  2520.         ln = (struct LockNode *)parent->fl_Key;
  2521.  
  2522.         parent_name = ln->ln_FullName;
  2523.         if(strcmp(parent_name,SMB_ROOT_DIR_NAME) == SAME)
  2524.             parent_name = NULL;
  2525.     }
  2526.     else
  2527.     {
  2528.         parent_name = NULL;
  2529.     }
  2530.  
  2531.     ConvertBString(sizeof(name),name,bcpl_name);
  2532.     TranslateCName(name,A2M);
  2533.  
  2534.     error = BuildFullName(parent_name,name,&full_name);
  2535.     if(error != OK)
  2536.         goto out;
  2537.  
  2538.     /* We need to find this file's parent directory, so that
  2539.      * in case the directory contents are currently being
  2540.      * examined, that process is restarted.
  2541.      */
  2542.     full_parent_name = AllocVecPooled(strlen(full_name)+3);
  2543.     if(full_parent_name == NULL)
  2544.     {
  2545.         error = ERROR_NO_FREE_STORE;
  2546.         goto out;
  2547.     }
  2548.  
  2549.     strcpy(full_parent_name,full_name);
  2550.  
  2551.     for(i = strlen(full_parent_name)-1 ; i >= 0 ; i--)
  2552.     {
  2553.         if(i == 0)
  2554.         {
  2555.             strcpy(full_parent_name,SMB_ROOT_DIR_NAME);
  2556.             break;
  2557.         }
  2558.         else if (full_parent_name[i] == SMB_PATH_SEPARATOR)
  2559.         {
  2560.             full_parent_name[i] = '\0';
  2561.             break;
  2562.         }
  2563.     }
  2564.  
  2565.     ln = FindLockNode(full_parent_name,NULL);
  2566.     if(ln != NULL)
  2567.         ln->ln_RestartExamine = TRUE;
  2568.  
  2569.     FreeVecPooled(full_parent_name);
  2570.     full_parent_name = NULL;
  2571.  
  2572.     SHOWSTRING(full_name);
  2573.  
  2574.     error = smba_open(ServerData,full_name,&file);
  2575.     if(error < 0)
  2576.     {
  2577.         error = MapErrnoToIoErr(error);
  2578.         goto out;
  2579.     }
  2580.  
  2581.     error = smba_getattr(file,&stat);
  2582.     if(error < 0)
  2583.     {
  2584.         error = MapErrnoToIoErr(error);
  2585.         goto out;
  2586.     }
  2587.  
  2588.     smba_close(file);
  2589.     file = NULL;
  2590.  
  2591.     if(stat.is_dir)
  2592.     {
  2593.         SHOWMSG("removing a directory");
  2594.  
  2595.         error = smba_rmdir(ServerData,full_name);
  2596.         if(error < 0)
  2597.         {
  2598.             SHOWVALUE(error);
  2599.  
  2600.             /* This is a little bit difficult to justify since
  2601.              * the error code may indicate a different cause,
  2602.              * but in practice 'EACCES' seems to be returned
  2603.              * if the directory to remove is not empty.
  2604.              */
  2605.             if(error == (-EACCES))
  2606.                 error = ERROR_DIRECTORY_NOT_EMPTY;
  2607.             else
  2608.                 error = MapErrnoToIoErr(error);
  2609.  
  2610.             goto out;
  2611.         }
  2612.     }
  2613.     else
  2614.     {
  2615.         SHOWMSG("removing a file");
  2616.  
  2617.         error = smba_remove(ServerData,full_name);
  2618.         if(error < 0)
  2619.         {
  2620.             SHOWVALUE(error);
  2621.  
  2622.             error = MapErrnoToIoErr(error);
  2623.             goto out;
  2624.         }
  2625.     }
  2626.  
  2627.     SHOWMSG("done.");
  2628.  
  2629.     result = DOSTRUE;
  2630.  
  2631.  out:
  2632.  
  2633.     FreeVecPooled(full_name);
  2634.     FreeVecPooled(full_parent_name);
  2635.     if(file != NULL)
  2636.         smba_close(file);
  2637.  
  2638.     (*error_ptr) = error;
  2639.  
  2640.     RETURN(result);
  2641.     return(result);
  2642. }
  2643.  
  2644. /****************************************************************************/
  2645.  
  2646. STATIC BPTR
  2647. Action_CreateDir(
  2648.     struct FileLock *    parent,
  2649.     APTR                bcpl_name,
  2650.     LONG *                error_ptr)
  2651. {
  2652.     BPTR result = ZERO;
  2653.     STRPTR full_name = NULL;
  2654.     struct LockNode * ln = NULL;
  2655.     STRPTR parent_name;
  2656.     STRPTR dir_name = NULL;
  2657.     smba_file_t * dir = NULL;
  2658.     STRPTR base_name;
  2659.     UBYTE name[MAX_FILENAME_LEN];
  2660.     LONG error;
  2661.     LONG i;
  2662.  
  2663.     ENTER();
  2664.  
  2665.     if(WriteProtected)
  2666.     {
  2667.         error = ERROR_DISK_WRITE_PROTECTED;
  2668.         goto out;
  2669.     }
  2670.  
  2671.     SHOWVALUE(parent);
  2672.  
  2673.     if(parent != NULL)
  2674.     {
  2675.         struct LockNode * ln = (struct LockNode *)parent->fl_Key;
  2676.  
  2677.         parent_name = ln->ln_FullName;
  2678.         if(strcmp(parent_name,SMB_ROOT_DIR_NAME) == SAME)
  2679.             parent_name = NULL;
  2680.     }
  2681.     else
  2682.     {
  2683.         parent_name = NULL;
  2684.     }
  2685.  
  2686.     ConvertBString(sizeof(name),name,bcpl_name);
  2687.     TranslateCName(name,A2M);
  2688.  
  2689.     error = BuildFullName(parent_name,name,&full_name);
  2690.     if(error != OK)
  2691.         goto out;
  2692.  
  2693.     dir_name = AllocVecPooled(strlen(full_name)+3);
  2694.     if(dir_name == NULL)
  2695.     {
  2696.         error = ERROR_NO_FREE_STORE;
  2697.         goto out;
  2698.     }
  2699.  
  2700.     strcpy(dir_name,full_name);
  2701.     base_name = NULL;
  2702.  
  2703.     for(i = strlen(dir_name)-1 ; i >= 0 ; i--)
  2704.     {
  2705.         if(i == 0)
  2706.         {
  2707.             base_name = full_name;
  2708.             strcpy(dir_name,SMB_ROOT_DIR_NAME);
  2709.             break;
  2710.         }
  2711.         else if (dir_name[i] == SMB_PATH_SEPARATOR)
  2712.         {
  2713.             base_name = &full_name[i+1];
  2714.             dir_name[i] = '\0';
  2715.             break;
  2716.         }
  2717.     }
  2718.  
  2719.     ln = AllocVecPooled(sizeof(*ln));
  2720.     if(ln == NULL)
  2721.     {
  2722.         error = ERROR_NO_FREE_STORE;
  2723.         goto out;
  2724.     }
  2725.  
  2726.     memset(ln,0,sizeof(*ln));
  2727.  
  2728.     ln->ln_FileLock.fl_Key        = (LONG)ln;
  2729.     ln->ln_FileLock.fl_Access    = EXCLUSIVE_LOCK;
  2730.     ln->ln_FileLock.fl_Task        = FileSystemPort;
  2731.     ln->ln_FileLock.fl_Volume    = MKBADDR(VolumeNode);
  2732.     ln->ln_FullName                = full_name;
  2733.  
  2734.     error = smba_open(ServerData,dir_name,&dir);
  2735.     if(error < 0)
  2736.     {
  2737.         error = MapErrnoToIoErr(error);
  2738.         goto out;
  2739.     }
  2740.  
  2741.     error = smba_mkdir(dir,base_name);
  2742.     if(error < 0)
  2743.     {
  2744.         error = MapErrnoToIoErr(error);
  2745.         goto out;
  2746.     }
  2747.  
  2748.     smba_close(dir);
  2749.     dir = NULL;
  2750.  
  2751.     SHOWSTRING(full_name);
  2752.  
  2753.     error = smba_open(ServerData,full_name,&ln->ln_File);
  2754.     if(error < 0)
  2755.     {
  2756.         error = MapErrnoToIoErr(error);
  2757.         goto out;
  2758.     }
  2759.  
  2760.     AddTail((struct List *)&LockList,(struct Node *)ln);
  2761.     result = MKBADDR(&ln->ln_FileLock);
  2762.     SHOWVALUE(&ln->ln_FileLock);
  2763.  
  2764.  out:
  2765.  
  2766.     if(dir != NULL)
  2767.         smba_close(dir);
  2768.  
  2769.     FreeVecPooled(dir_name);
  2770.  
  2771.     if(result == ZERO)
  2772.     {
  2773.         FreeVecPooled(full_name);
  2774.         FreeVecPooled(ln);
  2775.     }
  2776.  
  2777.     (*error_ptr) = error;
  2778.  
  2779.     RETURN(result);
  2780.     return(result);
  2781. }
  2782.  
  2783. /****************************************************************************/
  2784.  
  2785. STATIC BPTR
  2786. Action_LocateObject(
  2787.     struct FileLock *    parent,
  2788.     APTR                bcpl_name,
  2789.     LONG                mode,
  2790.     LONG *                error_ptr)
  2791. {
  2792.     BPTR result = ZERO;
  2793.     STRPTR full_name = NULL;
  2794.     struct LockNode * ln = NULL;
  2795.     STRPTR parent_name;
  2796.     UBYTE name[MAX_FILENAME_LEN];
  2797.     LONG error;
  2798.  
  2799.     ENTER();
  2800.  
  2801.     SHOWVALUE(parent);
  2802.  
  2803.     if(parent != NULL)
  2804.     {
  2805.         struct LockNode * ln = (struct LockNode *)parent->fl_Key;
  2806.  
  2807.         parent_name = ln->ln_FullName;
  2808.         if(strcmp(parent_name,SMB_ROOT_DIR_NAME) == SAME)
  2809.             parent_name = NULL;
  2810.     }
  2811.     else
  2812.     {
  2813.         parent_name = NULL;
  2814.     }
  2815.  
  2816.     ConvertBString(sizeof(name),name,bcpl_name);
  2817.     TranslateCName(name,A2M);
  2818.  
  2819.     if(IsReservedName(FilePart(name)))
  2820.     {
  2821.         error = ERROR_OBJECT_NOT_FOUND;
  2822.         goto out;
  2823.     }
  2824.  
  2825.     error = BuildFullName(parent_name,name,&full_name);
  2826.     if(error != OK)
  2827.         goto out;
  2828.  
  2829.     ln = AllocVecPooled(sizeof(*ln));
  2830.     if(ln == NULL)
  2831.     {
  2832.         error = ERROR_NO_FREE_STORE;
  2833.         goto out;
  2834.     }
  2835.  
  2836.     memset(ln,0,sizeof(*ln));
  2837.  
  2838.     ln->ln_FileLock.fl_Key        = (LONG)ln;
  2839.     ln->ln_FileLock.fl_Access    = (mode != EXCLUSIVE_LOCK) ? SHARED_LOCK : EXCLUSIVE_LOCK;
  2840.     ln->ln_FileLock.fl_Task        = FileSystemPort;
  2841.     ln->ln_FileLock.fl_Volume    = MKBADDR(VolumeNode);
  2842.     ln->ln_FullName                = full_name;
  2843.  
  2844.     error = CheckAccessModeCollision(full_name,ln->ln_FileLock.fl_Access);
  2845.     if(error != OK)
  2846.         goto out;
  2847.  
  2848.     SHOWSTRING(full_name);
  2849.  
  2850.     error = smba_open(ServerData,full_name,&ln->ln_File);
  2851.     if(error < 0)
  2852.     {
  2853.         error = MapErrnoToIoErr(error);
  2854.         goto out;
  2855.     }
  2856.  
  2857.     AddTail((struct List *)&LockList,(struct Node *)ln);
  2858.     result = MKBADDR(&ln->ln_FileLock);
  2859.     SHOWVALUE(&ln->ln_FileLock);
  2860.  
  2861.  out:
  2862.  
  2863.     if(result == ZERO)
  2864.     {
  2865.         FreeVecPooled(full_name);
  2866.         FreeVecPooled(ln);
  2867.     }
  2868.  
  2869.     (*error_ptr) = error;
  2870.  
  2871.     RETURN(result);
  2872.     return(result);
  2873. }
  2874.  
  2875. /****************************************************************************/
  2876.  
  2877. STATIC BPTR
  2878. Action_CopyDir(
  2879.     struct FileLock *    lock,
  2880.     LONG *                error_ptr)
  2881. {
  2882.     BPTR result = ZERO;
  2883.     STRPTR full_name = NULL;
  2884.     struct LockNode * source;
  2885.     struct LockNode * ln = NULL;
  2886.     LONG error = OK;
  2887.  
  2888.     ENTER();
  2889.  
  2890.     SHOWVALUE(lock);
  2891.  
  2892.     if(lock == NULL)
  2893.     {
  2894.         SHOWMSG("zero lock");
  2895.         goto out;
  2896.     }
  2897.  
  2898.     if(lock->fl_Access != SHARED_LOCK)
  2899.     {
  2900.         SHOWMSG("cannot duplicate exclusive lock");
  2901.         error = ERROR_OBJECT_IN_USE;
  2902.         goto out;
  2903.     }
  2904.  
  2905.     ln = AllocVecPooled(sizeof(*ln));
  2906.     if(ln == NULL)
  2907.     {
  2908.         error = ERROR_NO_FREE_STORE;
  2909.         goto out;
  2910.     }
  2911.  
  2912.     memset(ln,0,sizeof(*ln));
  2913.  
  2914.     source = (struct LockNode *)lock->fl_Key;
  2915.  
  2916.     full_name = AllocVecPooled(strlen(source->ln_FullName)+3);
  2917.     if(full_name == NULL)
  2918.     {
  2919.         error = ERROR_NO_FREE_STORE;
  2920.         goto out;
  2921.     }
  2922.  
  2923.     strcpy(full_name,source->ln_FullName);
  2924.  
  2925.     ln->ln_FileLock.fl_Key        = (LONG)ln;
  2926.     ln->ln_FileLock.fl_Access    = source->ln_FileLock.fl_Access;
  2927.     ln->ln_FileLock.fl_Task        = FileSystemPort;
  2928.     ln->ln_FileLock.fl_Volume    = MKBADDR(VolumeNode);
  2929.     ln->ln_FullName                = full_name;
  2930.  
  2931.     SHOWSTRING(full_name);
  2932.  
  2933.     error = smba_open(ServerData,full_name,&ln->ln_File);
  2934.     if(error < 0)
  2935.     {
  2936.         error = MapErrnoToIoErr(error);
  2937.         goto out;
  2938.     }
  2939.  
  2940.     AddTail((struct List *)&LockList,(struct Node *)ln);
  2941.     result = MKBADDR(&ln->ln_FileLock);
  2942.     SHOWVALUE(&ln->ln_FileLock);
  2943.  
  2944.  out:
  2945.  
  2946.     if(result == ZERO)
  2947.     {
  2948.         FreeVecPooled(full_name);
  2949.         FreeVecPooled(ln);
  2950.     }
  2951.  
  2952.     (*error_ptr) = error;
  2953.  
  2954.     RETURN(result);
  2955.     return(result);
  2956. }
  2957.  
  2958. /****************************************************************************/
  2959.  
  2960. STATIC LONG
  2961. Action_FreeLock(
  2962.     struct FileLock *    lock,
  2963.     LONG *                error_ptr)
  2964. {
  2965.     LONG result = DOSTRUE;
  2966.     struct LockNode * ln;
  2967.     LONG error = OK;
  2968.  
  2969.     ENTER();
  2970.  
  2971.     SHOWVALUE(lock);
  2972.  
  2973.     if(lock == NULL)
  2974.         goto out;
  2975.  
  2976.     ln = (struct LockNode *)lock->fl_Key;
  2977.  
  2978.     Remove((struct Node *)ln);
  2979.     smba_close(ln->ln_File);
  2980.     FreeVecPooled(ln->ln_FullName);
  2981.     FreeVecPooled(ln);
  2982.  
  2983.  out:
  2984.  
  2985.     (*error_ptr) = error;
  2986.  
  2987.     RETURN(result);
  2988.     return(result);
  2989. }
  2990.  
  2991. /****************************************************************************/
  2992.  
  2993. STATIC LONG
  2994. Action_SameLock(
  2995.     struct FileLock *    lock1,
  2996.     struct FileLock *    lock2,
  2997.     LONG *                error_ptr)
  2998. {
  2999.     LONG result = DOSFALSE;
  3000.     STRPTR name1;
  3001.     STRPTR name2;
  3002.     LONG error = OK;
  3003.  
  3004.     ENTER();
  3005.  
  3006.     SHOWVALUE(lock1);
  3007.     SHOWVALUE(lock2);
  3008.  
  3009.     if(lock1 != NULL)
  3010.     {
  3011.         struct LockNode * ln = (struct LockNode *)lock1->fl_Key;
  3012.  
  3013.         name1 = ln->ln_FullName;
  3014.     }
  3015.     else
  3016.     {
  3017.         name1 = SMB_ROOT_DIR_NAME;
  3018.     }
  3019.  
  3020.     if(lock2 != NULL)
  3021.     {
  3022.         struct LockNode * ln = (struct LockNode *)lock2->fl_Key;
  3023.  
  3024.         name2 = ln->ln_FullName;
  3025.     }
  3026.     else
  3027.     {
  3028.         name2 = SMB_ROOT_DIR_NAME;
  3029.     }
  3030.  
  3031.     SHOWSTRING(name1);
  3032.     SHOWSTRING(name2);
  3033.  
  3034.     if(Stricmp(name1,name2) == SAME)
  3035.         result = DOSTRUE;
  3036.  
  3037.     (*error_ptr) = error;
  3038.  
  3039.     RETURN(result);
  3040.     return(result);
  3041. }
  3042.  
  3043. /****************************************************************************/
  3044.  
  3045. STATIC LONG
  3046. Action_SetProtect(
  3047.     struct FileLock *    parent,
  3048.     APTR                bcpl_name,
  3049.     LONG                mask,
  3050.     LONG *                error_ptr)
  3051. {
  3052.     LONG result = DOSFALSE;
  3053.     STRPTR full_name = NULL;
  3054.     smba_file_t * file = NULL;
  3055.     STRPTR parent_name;
  3056.     UBYTE name[MAX_FILENAME_LEN];
  3057.     smba_stat_t stat;
  3058.     LONG error;
  3059.  
  3060.     ENTER();
  3061.  
  3062.     if(WriteProtected)
  3063.     {
  3064.         error = ERROR_DISK_WRITE_PROTECTED;
  3065.         goto out;
  3066.     }
  3067.  
  3068.     SHOWVALUE(parent);
  3069.  
  3070.     if(parent != NULL)
  3071.     {
  3072.         struct LockNode * ln = (struct LockNode *)parent->fl_Key;
  3073.  
  3074.         parent_name = ln->ln_FullName;
  3075.         if(strcmp(parent_name,SMB_ROOT_DIR_NAME) == SAME)
  3076.             parent_name = NULL;
  3077.     }
  3078.     else
  3079.     {
  3080.         parent_name = NULL;
  3081.     }
  3082.  
  3083.     ConvertBString(sizeof(name),name,bcpl_name);
  3084.     TranslateCName(name,A2M);
  3085.  
  3086.     error = BuildFullName(parent_name,name,&full_name);
  3087.     if(error != OK)
  3088.         goto out;
  3089.  
  3090.     SHOWSTRING(full_name);
  3091.  
  3092.     error = smba_open(ServerData,full_name,&file);
  3093.     if(error < 0)
  3094.     {
  3095.         error = MapErrnoToIoErr(error);
  3096.         goto out;
  3097.     }
  3098.  
  3099.     memset(&stat,0,sizeof(stat));
  3100.  
  3101.     mask ^= FIBF_READ | FIBF_WRITE | FIBF_EXECUTE | FIBF_DELETE;
  3102.  
  3103.     stat.atime = -1;
  3104.     stat.ctime = -1;
  3105.     stat.mtime = -1;
  3106.     stat.size = -1;
  3107.  
  3108.     if((mask & (FIBF_WRITE|FIBF_DELETE)) != (FIBF_WRITE|FIBF_DELETE))
  3109.     {
  3110.         SHOWMSG("write protection enabled");
  3111.         stat.is_wp = TRUE;
  3112.     }
  3113.     else
  3114.     {
  3115.         SHOWMSG("write protection disabled");
  3116.     }
  3117.  
  3118.     error = smba_setattr(file,&stat);
  3119.     if(error < 0)
  3120.     {
  3121.         error = MapErrnoToIoErr(error);
  3122.         goto out;
  3123.     }
  3124.  
  3125.     result = DOSTRUE;
  3126.  
  3127.  out:
  3128.  
  3129.     FreeVecPooled(full_name);
  3130.     if(file != NULL)
  3131.         smba_close(file);
  3132.  
  3133.     (*error_ptr) = error;
  3134.  
  3135.     RETURN(result);
  3136.     return(result);
  3137. }
  3138.  
  3139. /****************************************************************************/
  3140.  
  3141. STATIC LONG
  3142. Action_RenameObject(
  3143.     struct FileLock *    source_lock,
  3144.     APTR                source_bcpl_name,
  3145.     struct FileLock *    destination_lock,
  3146.     APTR                destination_bcpl_name,
  3147.     LONG *                error_ptr)
  3148. {
  3149.     struct LockNode * ln;
  3150.     LONG result = DOSFALSE;
  3151.     STRPTR full_source_name = NULL;
  3152.     STRPTR full_destination_name = NULL;
  3153.     UBYTE name[MAX_FILENAME_LEN];
  3154.     STRPTR parent_name;
  3155.     LONG error;
  3156.  
  3157.     ENTER();
  3158.  
  3159.     if(WriteProtected)
  3160.     {
  3161.         error = ERROR_DISK_WRITE_PROTECTED;
  3162.         goto out;
  3163.     }
  3164.  
  3165.     SHOWVALUE(source_lock);
  3166.     SHOWVALUE(destination_lock);
  3167.  
  3168.     if(source_lock != NULL)
  3169.     {
  3170.         ln = (struct LockNode *)source_lock->fl_Key;
  3171.  
  3172.         parent_name = ln->ln_FullName;
  3173.         if(strcmp(parent_name,SMB_ROOT_DIR_NAME) == SAME)
  3174.             parent_name = NULL;
  3175.     }
  3176.     else
  3177.     {
  3178.         parent_name = NULL;
  3179.     }
  3180.  
  3181.     ConvertBString(sizeof(name),name,source_bcpl_name);
  3182.     TranslateCName(name,A2M);
  3183.  
  3184.     error = BuildFullName(parent_name,name,&full_source_name);
  3185.     if(error != OK)
  3186.         goto out;
  3187.  
  3188.     if(destination_lock != NULL)
  3189.     {
  3190.         ln = (struct LockNode *)destination_lock->fl_Key;
  3191.  
  3192.         parent_name = ln->ln_FullName;
  3193.         if(strcmp(parent_name,SMB_ROOT_DIR_NAME) == SAME)
  3194.             parent_name = NULL;
  3195.     }
  3196.     else
  3197.     {
  3198.         parent_name = NULL;
  3199.     }
  3200.  
  3201.     ConvertBString(sizeof(name),name,destination_bcpl_name);
  3202.     TranslateCName(name,A2M);
  3203.  
  3204.     error = BuildFullName(parent_name,name,&full_destination_name);
  3205.     if(error != OK)
  3206.         goto out;
  3207.  
  3208.     error = NameAlreadyInUse(full_source_name);
  3209.     if(error != OK)
  3210.         goto out;
  3211.  
  3212.     error = NameAlreadyInUse(full_destination_name);
  3213.     if(error != OK)
  3214.         goto out;
  3215.  
  3216.     SHOWSTRING(full_source_name);
  3217.     SHOWSTRING(full_destination_name);
  3218.  
  3219.     error = smba_rename(ServerData,full_source_name,full_destination_name);
  3220.     if(error < 0)
  3221.     {
  3222.         error = MapErrnoToIoErr(error);
  3223.         goto out;
  3224.     }
  3225.  
  3226.     result = DOSTRUE;
  3227.  
  3228.  out:
  3229.  
  3230.     FreeVecPooled(full_source_name);
  3231.     FreeVecPooled(full_destination_name);
  3232.  
  3233.     (*error_ptr) = error;
  3234.  
  3235.     RETURN(result);
  3236.     return(result);
  3237. }
  3238.  
  3239. /****************************************************************************/
  3240.  
  3241. STATIC LONG
  3242. Action_DiskInfo(
  3243.     struct InfoData *    id,
  3244.     LONG *                error_ptr)
  3245. {
  3246.     LONG result = DOSTRUE;
  3247.     LONG block_size;
  3248.     LONG num_blocks;
  3249.     LONG num_blocks_free;
  3250.     LONG error;
  3251.  
  3252.     ENTER();
  3253.  
  3254.     memset(id,0,sizeof(*id));
  3255.  
  3256.     if(WriteProtected)
  3257.         id->id_DiskState = ID_WRITE_PROTECTED;
  3258.     else
  3259.         id->id_DiskState = ID_VALIDATED;
  3260.  
  3261.     error = smba_statfs(ServerData,&block_size,&num_blocks,&num_blocks_free);
  3262.     if(error >= 0)
  3263.     {
  3264.         SHOWMSG("got the disk data");
  3265.         SHOWVALUE(block_size);
  3266.         SHOWVALUE(num_blocks);
  3267.         SHOWVALUE(num_blocks_free);
  3268.  
  3269.         if(block_size <= 0)
  3270.             block_size = 512;
  3271.  
  3272.         if(block_size < 512)
  3273.         {
  3274.             num_blocks        /= (512 / block_size);
  3275.             num_blocks_free    /= (512 / block_size);
  3276.         }
  3277.         else if (block_size > 512)
  3278.         {
  3279.             num_blocks        *= (block_size / 512);
  3280.             num_blocks_free    *= (block_size / 512);
  3281.         }
  3282.  
  3283.         id->id_NumBlocks        = num_blocks;
  3284.         id->id_NumBlocksUsed    = num_blocks - num_blocks_free;
  3285.         id->id_BytesPerBlock    = 512;
  3286.         id->id_DiskType            = ID_DOS_DISK;
  3287.         id->id_VolumeNode        = MKBADDR(VolumeNode);
  3288.         id->id_InUse            = NOT (IsListEmpty((struct List *)&FileList) && IsListEmpty((struct List *)&LockList));
  3289.  
  3290.         if(id->id_NumBlocks == 0)
  3291.             id->id_NumBlocks = 1;
  3292.  
  3293.         if(id->id_NumBlocksUsed == 0)
  3294.             id->id_NumBlocksUsed = 1;
  3295.     }
  3296.     else
  3297.     {
  3298.         SHOWMSG("could not get any disk data");
  3299.  
  3300.         id->id_NumBlocks        = 1;
  3301.         id->id_NumBlocksUsed    = 1;
  3302.         id->id_BytesPerBlock    = 512;
  3303.         id->id_DiskType            = ID_NO_DISK_PRESENT;
  3304.  
  3305.         error = MapErrnoToIoErr(error);
  3306.         result = DOSFALSE;
  3307.     }
  3308.  
  3309.     SHOWVALUE(id->id_NumBlocks);
  3310.     SHOWVALUE(id->id_NumBlocksUsed);
  3311.     SHOWVALUE(id->id_BytesPerBlock);
  3312.     SHOWVALUE(id->id_DiskType);
  3313.     SHOWVALUE(id->id_VolumeNode);
  3314.     SHOWVALUE(id->id_InUse);
  3315.  
  3316.     (*error_ptr) = error;
  3317.  
  3318.     RETURN(result);
  3319.     return(result);
  3320. }
  3321.  
  3322. STATIC LONG
  3323. Action_Info(
  3324.     struct FileLock *    lock,
  3325.     struct InfoData *    id,
  3326.     LONG *                error_ptr)
  3327. {
  3328.     LONG result;
  3329.  
  3330.     ENTER();
  3331.  
  3332.     SHOWVALUE(lock);
  3333.  
  3334.     if(lock == NULL || lock->fl_Volume != MKBADDR(VolumeNode))
  3335.     {
  3336.         SHOWMSG("volume node does not match");
  3337.  
  3338.         result = DOSFALSE;
  3339.  
  3340.         (*error_ptr) = ERROR_NO_DISK;
  3341.     }
  3342.     else
  3343.     {
  3344.         result = Action_DiskInfo(id,error_ptr);
  3345.     }
  3346.  
  3347.     RETURN(result);
  3348.     return(result);
  3349. }
  3350.  
  3351. /****************************************************************************/
  3352.  
  3353. STATIC LONG
  3354. Action_ExamineObject(
  3355.     struct FileLock *        lock,
  3356.     struct FileInfoBlock *    fib,
  3357.     LONG *                    error_ptr)
  3358. {
  3359.     LONG result = DOSFALSE;
  3360.     LONG error = OK;
  3361.  
  3362.     ENTER();
  3363.  
  3364.     SHOWVALUE(lock);
  3365.  
  3366.     memset(fib,0,sizeof(*fib));
  3367.  
  3368.     if(lock == NULL)
  3369.     {
  3370.         STRPTR volume_name = BADDR(VolumeNode->dol_Name);
  3371.         LONG len = volume_name[0];
  3372.  
  3373.         SHOWMSG("ZERO root lock");
  3374.  
  3375.         memcpy(fib->fib_FileName+1,volume_name+1,len);
  3376.         fib->fib_FileName[0] = len;
  3377.  
  3378.         fib->fib_DirEntryType    = ST_ROOT;
  3379.         fib->fib_EntryType        = ST_ROOT;
  3380.         fib->fib_NumBlocks        = 1;
  3381.         fib->fib_Date            = VolumeNode->dol_misc.dol_volume.dol_VolumeDate;
  3382.         fib->fib_DiskKey        = -1;
  3383.         fib->fib_Protection        = FIBF_OTR_READ|FIBF_OTR_EXECUTE|FIBF_OTR_WRITE|FIBF_OTR_DELETE|
  3384.                                   FIBF_GRP_READ|FIBF_GRP_EXECUTE|FIBF_GRP_WRITE|FIBF_GRP_DELETE;
  3385.     }
  3386.     else
  3387.     {
  3388.         struct LockNode * ln = (struct LockNode *)lock->fl_Key;
  3389.         LONG seconds;
  3390.         smba_stat_t stat;
  3391.  
  3392.         error = smba_getattr(ln->ln_File,&stat);
  3393.         if(error < 0)
  3394.         {
  3395.             SHOWMSG("information not available");
  3396.  
  3397.             error = MapErrnoToIoErr(error);
  3398.             goto out;
  3399.         }
  3400.  
  3401.         seconds = stat.mtime - UNIX_TIME_OFFSET - GetTimeZoneDelta();
  3402.         if(seconds < 0)
  3403.             seconds = 0;
  3404.  
  3405.         fib->fib_Date.ds_Days    = (seconds / (24 * 60 * 60));
  3406.         fib->fib_Date.ds_Minute    = (seconds % (24 * 60 * 60)) / 60;
  3407.         fib->fib_Date.ds_Tick    = (seconds % 60) * TICKS_PER_SECOND;
  3408.  
  3409.         SHOWSTRING(ln->ln_FullName);
  3410.  
  3411.         if(strcmp(ln->ln_FullName,SMB_ROOT_DIR_NAME) == SAME)
  3412.         {
  3413.             STRPTR volume_name = BADDR(VolumeNode->dol_Name);
  3414.             LONG len = volume_name[0];
  3415.  
  3416.             SHOWMSG("root lock");
  3417.  
  3418.             memcpy(fib->fib_FileName+1,volume_name+1,len);
  3419.             fib->fib_FileName[0] = len;
  3420.  
  3421.             fib->fib_DirEntryType    = ST_ROOT;
  3422.             fib->fib_EntryType        = ST_ROOT;
  3423.             fib->fib_NumBlocks        = 1;
  3424.             fib->fib_Protection        = FIBF_OTR_READ|FIBF_OTR_EXECUTE|FIBF_OTR_WRITE|FIBF_OTR_DELETE|
  3425.                                       FIBF_GRP_READ|FIBF_GRP_EXECUTE|FIBF_GRP_WRITE|FIBF_GRP_DELETE;
  3426.         }
  3427.         else
  3428.         {
  3429.             STRPTR name;
  3430.             LONG i;
  3431.  
  3432.             name = ln->ln_FullName;
  3433.             for(i = strlen(name)-1 ; i >= 0 ; i--)
  3434.             {
  3435.                 if(name[i] == SMB_PATH_SEPARATOR)
  3436.                 {
  3437.                     name = &name[i+1];
  3438.                     break;
  3439.                 }
  3440.             }
  3441.  
  3442.             /* Just checking: will the name fit? */
  3443.             if(strlen(name) >= sizeof(fib->fib_FileName))
  3444.             {
  3445.                 error = ERROR_INVALID_COMPONENT_NAME;
  3446.                 goto out;
  3447.             }
  3448.  
  3449.             ConvertCString(sizeof(fib->fib_FileName),fib->fib_FileName,name);
  3450.             TranslateBName(fib->fib_FileName,M2A);
  3451.  
  3452.             fib->fib_DirEntryType    = stat.is_dir ? ST_USERDIR : ST_FILE;
  3453.             fib->fib_EntryType        = fib->fib_DirEntryType;
  3454.             fib->fib_NumBlocks        = (stat.size + 511) / 512;
  3455.             fib->fib_Size            = stat.size;
  3456.             fib->fib_Protection        = FIBF_OTR_READ|FIBF_OTR_EXECUTE|FIBF_OTR_WRITE|FIBF_OTR_DELETE|
  3457.                                       FIBF_GRP_READ|FIBF_GRP_EXECUTE|FIBF_GRP_WRITE|FIBF_GRP_DELETE;
  3458.  
  3459.             if(stat.is_wp)
  3460.                 fib->fib_Protection ^= (FIBF_OTR_WRITE|FIBF_OTR_DELETE|FIBF_GRP_WRITE|FIBF_GRP_DELETE|FIBF_WRITE|FIBF_DELETE);
  3461.  
  3462.             if(NOT stat.is_dir)
  3463.                 fib->fib_DiskKey = -1;
  3464.         }
  3465.     }
  3466.  
  3467.     result = DOSTRUE;
  3468.  
  3469.     D(("fib->fib_FileName = \"%b\"",MKBADDR(fib->fib_FileName)));
  3470.     SHOWVALUE(fib->fib_DirEntryType);
  3471.     SHOWVALUE(fib->fib_NumBlocks);
  3472.     SHOWVALUE(fib->fib_Size);
  3473.     SHOWVALUE(fib->fib_Date.ds_Days);
  3474.     SHOWVALUE(fib->fib_Date.ds_Minute);
  3475.     SHOWVALUE(fib->fib_Date.ds_Tick);
  3476.     SHOWVALUE(fib->fib_DiskKey);
  3477.  
  3478.  out:
  3479.  
  3480.     (*error_ptr) = error;
  3481.  
  3482.     RETURN(result);
  3483.     return(result);
  3484. }
  3485.  
  3486. /****************************************************************************/
  3487.  
  3488. STATIC BOOL
  3489. NameIsAcceptable(STRPTR name,LONG max_len)
  3490. {
  3491.     BOOL result = FALSE;
  3492.     UBYTE c;
  3493.  
  3494.     /* This takes care of "." and "..". */
  3495.     if(name[0] == '.' && (name[1] == '\0' || (name[1] == '.' && name[2] == '\0')))
  3496.         goto out;
  3497.  
  3498.     /* Now for embedded '/', ':' and '\' characters and
  3499.      * names that just don't want to fit.
  3500.      */
  3501.     while((c = (*name++)) != '\0')
  3502.     {
  3503.         max_len--;
  3504.         if(max_len == 0 || c == '/' || c == ':' || c == SMB_PATH_SEPARATOR)
  3505.             goto out;
  3506.     }
  3507.  
  3508.     result = TRUE;
  3509.  
  3510.  out:
  3511.  
  3512.     return(result);
  3513. }
  3514.  
  3515. /****************************************************************************/
  3516.  
  3517. static int
  3518. dir_scan_callback_func_exnext(
  3519.     struct FileInfoBlock *    fib,
  3520.     int                        fpos,
  3521.     int                        nextpos,
  3522.     char *                    name,
  3523.     int                        eof,
  3524.     smba_stat_t *            stat)
  3525. {
  3526.     int result;
  3527.  
  3528.     ENTER();
  3529.  
  3530.     D((" '%s'",name));
  3531.     D(("   is_dir=%ld is_wp=%ld is_hidden=%ld size=%ld",
  3532.         stat->is_dir,stat->is_wp,stat->is_hidden,stat->size));
  3533.     D(("   fpos=%ld nextpos=%ld eof=%ld",fpos,nextpos,eof));
  3534.  
  3535.     /* Skip file and drawer names that we wouldn't be
  3536.      * able to handle in the first place.
  3537.      */
  3538.     if(NameIsAcceptable((STRPTR)name,sizeof(fib->fib_FileName)) && NOT (stat->is_hidden && OmitHidden))
  3539.     {
  3540.         LONG seconds;
  3541.  
  3542.         ConvertCString(sizeof(fib->fib_FileName),fib->fib_FileName,name);
  3543.         TranslateBName(fib->fib_FileName,M2A);
  3544.  
  3545.         fib->fib_DirEntryType    = stat->is_dir ? ST_USERDIR : ST_FILE;
  3546.         fib->fib_EntryType        = fib->fib_DirEntryType;
  3547.         fib->fib_NumBlocks        = (stat->size + 511) / 512;
  3548.         fib->fib_Size            = stat->size;
  3549.         fib->fib_Protection        = FIBF_OTR_READ|FIBF_OTR_EXECUTE|FIBF_OTR_WRITE|FIBF_OTR_DELETE|
  3550.                                   FIBF_GRP_READ|FIBF_GRP_EXECUTE|FIBF_GRP_WRITE|FIBF_GRP_DELETE;
  3551.  
  3552.         if(stat->is_wp)
  3553.             fib->fib_Protection ^= (FIBF_OTR_WRITE|FIBF_OTR_DELETE|FIBF_GRP_WRITE|FIBF_GRP_DELETE|FIBF_WRITE|FIBF_DELETE);
  3554.  
  3555.         seconds = stat->mtime - UNIX_TIME_OFFSET - GetTimeZoneDelta();
  3556.         if(seconds < 0)
  3557.             seconds = 0;
  3558.  
  3559.         fib->fib_Date.ds_Days    = (seconds / (24 * 60 * 60));
  3560.         fib->fib_Date.ds_Minute    = (seconds % (24 * 60 * 60)) / 60;
  3561.         fib->fib_Date.ds_Tick    = (seconds % 60) * TICKS_PER_SECOND;
  3562.  
  3563.         result = 1;
  3564.     }
  3565.     else
  3566.     {
  3567.         result = 0;
  3568.     }
  3569.  
  3570.     fib->fib_DiskKey = eof ? -1 : nextpos;
  3571.  
  3572.     RETURN(result);
  3573.     return(result);
  3574. }
  3575.  
  3576. STATIC LONG
  3577. Action_ExamineNext(
  3578.     struct FileLock *        lock,
  3579.     struct FileInfoBlock *    fib,
  3580.     LONG *                    error_ptr)
  3581. {
  3582.     struct LockNode * ln;
  3583.     LONG result = DOSFALSE;
  3584.     LONG error = OK;
  3585.     long offset;
  3586.     int count;
  3587.  
  3588.     ENTER();
  3589.  
  3590.     SHOWVALUE(lock);
  3591.  
  3592.     if(fib->fib_DiskKey == -1)
  3593.     {
  3594.         SHOWMSG("scanning finished.");
  3595.         error = ERROR_NO_MORE_ENTRIES;
  3596.         goto out;
  3597.     }
  3598.  
  3599.     if(lock == NULL)
  3600.     {
  3601.         SHOWMSG("invalid lock");
  3602.         error = ERROR_INVALID_LOCK;
  3603.         goto out;
  3604.     }
  3605.  
  3606.     offset = fib->fib_DiskKey;
  3607.  
  3608.     ln = (struct LockNode *)lock->fl_Key;
  3609.  
  3610.     /* Check if we should restart scanning the directory
  3611.      * contents. This is tricky at best and may produce
  3612.      * irritating results :(
  3613.      */
  3614.     if(ln->ln_RestartExamine)
  3615.     {
  3616.         offset = 0;
  3617.         ln->ln_RestartExamine = FALSE;
  3618.     }
  3619.  
  3620.     memset(fib,0,sizeof(*fib));
  3621.  
  3622.     SHOWMSG("calling 'smba_readdir'");
  3623.     SHOWVALUE(offset);
  3624.  
  3625.     count = smba_readdir(ln->ln_File,offset,fib,(smba_callback_t)dir_scan_callback_func_exnext);
  3626.  
  3627.     SHOWVALUE(count);
  3628.  
  3629.     if(count == 0 || fib->fib_FileName[0] == '\0')
  3630.     {
  3631.         SHOWMSG("nothing to be read");
  3632.         fib->fib_DiskKey = -1;
  3633.  
  3634.         error = ERROR_NO_MORE_ENTRIES;
  3635.         goto out;
  3636.     }
  3637.     else if (count == (-EIO))
  3638.     {
  3639.         SHOWMSG("ouch! directory read error");
  3640.         fib->fib_DiskKey = -1;
  3641.  
  3642.         error = ERROR_NO_DEFAULT_DIR;
  3643.         goto out;
  3644.     }
  3645.     else if (count < 0)
  3646.     {
  3647.         SHOWMSG("error whilst scanning");
  3648.         SHOWVALUE(count);
  3649.         fib->fib_DiskKey = -1;
  3650.  
  3651.         error = MapErrnoToIoErr(count);
  3652.         goto out;
  3653.     }
  3654.  
  3655.     result = DOSTRUE;
  3656.  
  3657.  out:
  3658.  
  3659.     (*error_ptr) = error;
  3660.  
  3661.     RETURN(result);
  3662.     return(result);
  3663. }
  3664.  
  3665. /****************************************************************************/
  3666.  
  3667. struct ExAllContext
  3668. {
  3669.     struct ExAllData *        ec_Last;
  3670.     struct ExAllData *        ec_Next;
  3671.     ULONG                    ec_BytesLeft;
  3672.     ULONG                    ec_MinSize;
  3673.     struct ExAllControl *     ec_Control;
  3674.     ULONG                    ec_Type;
  3675.     LONG                    ec_Error;
  3676.     BOOL                    ec_FirstAttempt;
  3677. };
  3678.  
  3679. static int
  3680. dir_scan_callback_func_exall(
  3681.     struct ExAllContext *    ec,
  3682.     int                        fpos,
  3683.     int                        nextpos,
  3684.     char *                    name,
  3685.     int                        eof,
  3686.     smba_stat_t *            stat)
  3687. {
  3688.     int result = 0;
  3689.  
  3690.     ENTER();
  3691.  
  3692.     D((" '%s'",name));
  3693.     D(("   is_dir=%ld is_wp=%ld is_hidden=%ld size=%ld",
  3694.         stat->is_dir,stat->is_wp,stat->is_hidden,stat->size));
  3695.     D(("   fpos=%ld nextpos=%ld eof=%ld",fpos,nextpos,eof));
  3696.  
  3697.     /* Skip file and drawer names that we wouldn't be
  3698.      * able to handle in the first place.
  3699.      */
  3700.     if(NameIsAcceptable((STRPTR)name,MAX_FILENAME_LEN) && NOT (stat->is_hidden && OmitHidden))
  3701.     {
  3702.         struct ExAllData * ed;
  3703.         ULONG size;
  3704.         ULONG type = ec->ec_Type;
  3705.         BOOL take_it;
  3706.  
  3707.         size = (ec->ec_MinSize + strlen(name)+1 + 3) & ~3;
  3708.         SHOWVALUE(size);
  3709.         if(size > ec->ec_BytesLeft)
  3710.         {
  3711.             D(("size %ld > ec->ec_BytesLeft %ld",size,ec->ec_BytesLeft));
  3712.  
  3713.             /* If this is the first directory entry,
  3714.              * stop the entire process before it has
  3715.              * really begun.
  3716.              */
  3717.             if(ec->ec_FirstAttempt)
  3718.             {
  3719.                 SHOWMSG("this was the first read attempt.");
  3720.                 ec->ec_Control->eac_Entries = 0;
  3721.                 ec->ec_Error = ERROR_NO_FREE_STORE;
  3722.             }
  3723.             else
  3724.             {
  3725.                 SHOWMSG("try again");
  3726.                 ec->ec_Error = 0;
  3727.             }
  3728.  
  3729.             result = 1;
  3730.             goto out;
  3731.         }
  3732.  
  3733.         ed = ec->ec_Next;
  3734.  
  3735.         ed->ed_Next = NULL;
  3736.         ed->ed_Name = (STRPTR)(((ULONG)ed) + ec->ec_MinSize);
  3737.         strcpy(ed->ed_Name,name);
  3738.  
  3739.         TranslateCName(ed->ed_Name,M2A);
  3740.  
  3741.         if(type >= ED_TYPE)
  3742.             ed->ed_Type = stat->is_dir ? ST_USERDIR : ST_FILE;
  3743.  
  3744.         if(type >= ED_SIZE)
  3745.             ed->ed_Size = stat->size;
  3746.  
  3747.         if(type >= ED_PROTECTION)
  3748.         {
  3749.             ed->ed_Prot = FIBF_OTR_READ|FIBF_OTR_EXECUTE|FIBF_OTR_WRITE|FIBF_OTR_DELETE|
  3750.                           FIBF_GRP_READ|FIBF_GRP_EXECUTE|FIBF_GRP_WRITE|FIBF_GRP_DELETE;
  3751.  
  3752.             if(stat->is_wp)
  3753.                 ed->ed_Prot ^= (FIBF_OTR_WRITE|FIBF_OTR_DELETE|FIBF_GRP_WRITE|FIBF_GRP_DELETE|FIBF_WRITE|FIBF_DELETE);
  3754.         }
  3755.  
  3756.         if(type >= ED_DATE)
  3757.         {
  3758.             LONG seconds;
  3759.  
  3760.             seconds = stat->mtime - UNIX_TIME_OFFSET - GetTimeZoneDelta();
  3761.             if(seconds < 0)
  3762.                 seconds = 0;
  3763.  
  3764.             ed->ed_Days        = (seconds / (24 * 60 * 60));
  3765.             ed->ed_Mins     = (seconds % (24 * 60 * 60)) / 60;
  3766.             ed->ed_Ticks    = (seconds % 60) * TICKS_PER_SECOND;
  3767.         }
  3768.  
  3769.         if(type >= ED_COMMENT)
  3770.             ed->ed_Comment = "";
  3771.  
  3772.         if(type >= ED_OWNER)
  3773.             ed->ed_OwnerUID = ed->ed_OwnerGID = 0;
  3774.  
  3775.         take_it = TRUE;
  3776.  
  3777.         if(ec->ec_Control->eac_MatchString != NULL)
  3778.         {
  3779.             SHOWMSG("checking against match string");
  3780.             if(NOT MatchPatternNoCase(ec->ec_Control->eac_MatchString,ed->ed_Name))
  3781.             {
  3782.                 SHOWMSG("does not match");
  3783.                 take_it = FALSE;
  3784.             }
  3785.         }
  3786.  
  3787.         if(take_it && ec->ec_Control->eac_MatchFunc != NULL)
  3788.         {
  3789.             SHOWMSG("calling match func");
  3790.  
  3791.             /* NOTE: the order of the parameters passed to the match hook
  3792.              *       function can be somewhat confusing. For standard
  3793.              *       hook functions, the order of the parameters and the
  3794.              *       registers they go into is hook=A0, object=A2,
  3795.              *       message=A1. However, the documentation for the 'ExAll()'
  3796.              *       function always lists them in ascending order, that is
  3797.              *       hook=A0, message=A1, object=A2, which can lead to
  3798.              *       quite some confusion and strange errors.
  3799.              */
  3800.             if(NOT CallHookPkt(ec->ec_Control->eac_MatchFunc,&type,ed))
  3801.             {
  3802.                 SHOWMSG("does not match");
  3803.                 take_it = FALSE;
  3804.             }
  3805.         }
  3806.  
  3807.         if(take_it)
  3808.         {
  3809.             SHOWMSG("registering new entry");
  3810.  
  3811.             if(ec->ec_Last != NULL)
  3812.                 ec->ec_Last->ed_Next = ed;
  3813.  
  3814.             ec->ec_Last = ed;
  3815.             ec->ec_Next = (struct ExAllData *)(((ULONG)ed) + size);
  3816.             ec->ec_BytesLeft -= size;
  3817.             ec->ec_Control->eac_Entries++;
  3818.  
  3819.             SHOWVALUE(ec->ec_Last->ed_Next);
  3820.             SHOWVALUE(ed->ed_Name);
  3821.             SHOWVALUE(ed->ed_Comment);
  3822.         }
  3823.     }
  3824.  
  3825.     ec->ec_Control->eac_LastKey = (ULONG)(eof ? -1 : nextpos);
  3826.  
  3827.  out:
  3828.  
  3829.     ec->ec_FirstAttempt = FALSE;
  3830.  
  3831.     RETURN(result);
  3832.     return(result);
  3833. }
  3834.  
  3835. STATIC LONG
  3836. Action_ExamineAll(
  3837.     struct FileLock *        lock,
  3838.     struct ExAllData *        ed,
  3839.     ULONG                    size,
  3840.     ULONG                    type,
  3841.     struct ExAllControl *    eac,
  3842.     LONG *                    error_ptr)
  3843. {
  3844.     struct ExAllContext ec;
  3845.     struct LockNode * ln;
  3846.     LONG result = DOSFALSE;
  3847.     LONG error = OK;
  3848.     LONG offset;
  3849.     int count;
  3850.  
  3851.     ENTER();
  3852.  
  3853.     SHOWVALUE(lock);
  3854.  
  3855.     SHOWVALUE(eac->eac_LastKey);
  3856.  
  3857.     eac->eac_Entries = 0;
  3858.     ed->ed_Next = NULL;
  3859.  
  3860.     if(eac->eac_LastKey == (ULONG)-1)
  3861.     {
  3862.         SHOWMSG("scanning finished.");
  3863.         error = ERROR_NO_MORE_ENTRIES;
  3864.         goto out;
  3865.     }
  3866.  
  3867.     if(lock == NULL)
  3868.     {
  3869.         SHOWMSG("invalid lock");
  3870.         error = ERROR_INVALID_LOCK;
  3871.         goto out;
  3872.     }
  3873.  
  3874.     if(type < ED_NAME || type > ED_OWNER)
  3875.     {
  3876.         D(("type %ld not supported",type));
  3877.         error = ERROR_BAD_NUMBER;
  3878.         goto out;
  3879.     }
  3880.  
  3881.     SHOWVALUE(type);
  3882.  
  3883.     memset(&ec,0,sizeof(ec));
  3884.  
  3885.     ec.ec_Next            = ed;
  3886.     ec.ec_BytesLeft        = size;
  3887.     ec.ec_Control        = eac;
  3888.     ec.ec_Type            = type;
  3889.     ec.ec_Error            = ERROR_NO_MORE_ENTRIES;
  3890.     ec.ec_FirstAttempt    = TRUE;
  3891.  
  3892.     switch(type)
  3893.     {
  3894.         case ED_NAME:
  3895.  
  3896.             ec.ec_MinSize = offsetof(struct ExAllData,ed_Type);
  3897.             break;
  3898.  
  3899.         case ED_TYPE:
  3900.  
  3901.             ec.ec_MinSize = offsetof(struct ExAllData,ed_Size);
  3902.             break;
  3903.  
  3904.         case ED_SIZE:
  3905.  
  3906.             ec.ec_MinSize = offsetof(struct ExAllData,ed_Prot);
  3907.             break;
  3908.  
  3909.         case ED_PROTECTION:
  3910.  
  3911.             ec.ec_MinSize = offsetof(struct ExAllData,ed_Days);
  3912.             break;
  3913.  
  3914.         case ED_DATE:
  3915.  
  3916.             ec.ec_MinSize = offsetof(struct ExAllData,ed_Comment);
  3917.             break;
  3918.  
  3919.         case ED_COMMENT:
  3920.  
  3921.             ec.ec_MinSize = offsetof(struct ExAllData,ed_OwnerUID);
  3922.             break;
  3923.  
  3924.         case ED_OWNER:
  3925.  
  3926.             ec.ec_MinSize = sizeof(struct ExAllData);
  3927.             break;
  3928.     }
  3929.  
  3930.     SHOWVALUE(ec.ec_MinSize);
  3931.  
  3932.     offset = eac->eac_LastKey;
  3933.  
  3934.     ln = (struct LockNode *)lock->fl_Key;
  3935.  
  3936.     /* Check if we should restart scanning the directory
  3937.      * contents. This is tricky at best and may produce
  3938.      * irritating results :(
  3939.      */
  3940.     if(ln->ln_RestartExamine)
  3941.     {
  3942.         offset = 0;
  3943.  
  3944.         ln->ln_RestartExamine = FALSE;
  3945.     }
  3946.  
  3947.     if(offset == 0)
  3948.     {
  3949.         smba_stat_t stat;
  3950.  
  3951.         SHOWMSG("first invocation");
  3952.  
  3953.         SHOWMSG("getting file attributes");
  3954.         error = smba_getattr(ln->ln_File,&stat);
  3955.         if(error < 0)
  3956.         {
  3957.             SHOWMSG("didn't work");
  3958.             error = MapErrnoToIoErr(error);
  3959.             eac->eac_LastKey = (ULONG)-1;
  3960.             goto out;
  3961.         }
  3962.  
  3963.         if(NOT stat.is_dir)
  3964.         {
  3965.             SHOWMSG("lock does not refer to a directory");
  3966.             error = ERROR_OBJECT_WRONG_TYPE;
  3967.             eac->eac_LastKey = (ULONG)-1;
  3968.             goto out;
  3969.         }
  3970.     }
  3971.  
  3972.     SHOWMSG("calling 'smba_readdir'");
  3973.     SHOWVALUE(offset);
  3974.  
  3975.     count = smba_readdir(ln->ln_File,offset,&ec,(smba_callback_t)dir_scan_callback_func_exall);
  3976.  
  3977.     SHOWVALUE(count);
  3978.  
  3979.     if(count == 0 || eac->eac_Entries == 0)
  3980.     {
  3981.         SHOWMSG("nothing to be read");
  3982.         if(ec.ec_Error != OK)
  3983.         {
  3984.             SHOWMSG("flagging an error");
  3985.             SHOWVALUE(ec.ec_Error);
  3986.             eac->eac_LastKey = (ULONG)-1;
  3987.             error = ec.ec_Error;
  3988.         }
  3989.  
  3990.         goto out;
  3991.     }
  3992.     else if (count == (-EIO))
  3993.     {
  3994.         SHOWMSG("ouch! directory read error");
  3995.         eac->eac_LastKey = (ULONG)-1;
  3996.  
  3997.         error = ERROR_NO_DEFAULT_DIR;
  3998.         goto out;
  3999.     }
  4000.     else if (count < 0)
  4001.     {
  4002.         SHOWMSG("error whilst scanning");
  4003.         eac->eac_LastKey = (ULONG)-1;
  4004.  
  4005.         error = MapErrnoToIoErr(count);
  4006.         goto out;
  4007.     }
  4008.  
  4009.     SHOWMSG("ok");
  4010.     result = DOSTRUE;
  4011.  
  4012.  out:
  4013.  
  4014.     #if DEBUG
  4015.     {
  4016.         SHOWVALUE(eac->eac_Entries);
  4017.  
  4018.         while(ed != NULL)
  4019.         {
  4020.             SHOWSTRING(ed->ed_Name);
  4021.  
  4022.             ed = ed->ed_Next;
  4023.         }
  4024.     }
  4025.     #endif /* DEBUG */
  4026.  
  4027.     (*error_ptr) = error;
  4028.  
  4029.     RETURN(result);
  4030.     return(result);
  4031. }
  4032.  
  4033. /****************************************************************************/
  4034.  
  4035. STATIC LONG
  4036. Action_Find(
  4037.     LONG                    action,
  4038.     struct FileHandle *        fh,
  4039.     struct FileLock *        parent,
  4040.     APTR                    bcpl_name,
  4041.     LONG *                    error_ptr)
  4042. {
  4043.     LONG result = DOSFALSE;
  4044.     STRPTR parent_path = NULL;
  4045.     STRPTR full_name = NULL;
  4046.     struct FileNode * fn = NULL;
  4047.     STRPTR parent_name;
  4048.     UBYTE name[MAX_FILENAME_LEN];
  4049.     BOOL create_new_file;
  4050.     LONG error;
  4051.  
  4052.     ENTER();
  4053.  
  4054.     switch(action)
  4055.     {
  4056.         case ACTION_FINDINPUT:
  4057.             D(("ACTION_FINDINPUT [Open(\"%b\",MODE_OLDFILE)]",MKBADDR(bcpl_name)));
  4058.             break;
  4059.  
  4060.         case ACTION_FINDOUTPUT:
  4061.             D(("ACTION_FINDOUTPUT [Open(\"%b\",MODE_NEWFILE)]",MKBADDR(bcpl_name)));
  4062.             break;
  4063.  
  4064.         case ACTION_FINDUPDATE:
  4065.             D(("ACTION_FINDUPDATE [Open(\"%b\",MODE_READWRITE)]",MKBADDR(bcpl_name)));
  4066.             break;
  4067.     }
  4068.  
  4069.     SHOWVALUE(parent);
  4070.  
  4071.     if(parent != NULL)
  4072.     {
  4073.         struct LockNode * ln = (struct LockNode *)parent->fl_Key;
  4074.  
  4075.         parent_name = ln->ln_FullName;
  4076.         if(strcmp(parent_name,SMB_ROOT_DIR_NAME) == SAME)
  4077.             parent_name = NULL;
  4078.     }
  4079.     else
  4080.     {
  4081.         parent_name = NULL;
  4082.     }
  4083.  
  4084.     ConvertBString(sizeof(name),name,bcpl_name);
  4085.     TranslateCName(name,A2M);
  4086.  
  4087.     if(IsReservedName(FilePart(name)))
  4088.     {
  4089.         error = ERROR_OBJECT_NOT_FOUND;
  4090.         goto out;
  4091.     }
  4092.  
  4093.     error = BuildFullName(parent_name,name,&full_name);
  4094.     if(error != OK)
  4095.         goto out;
  4096.  
  4097.     fn = AllocVecPooled(sizeof(*fn));
  4098.     if(fn == NULL)
  4099.     {
  4100.         error = ERROR_NO_FREE_STORE;
  4101.         goto out;
  4102.     }
  4103.  
  4104.     memset(fn,0,sizeof(*fn));
  4105.  
  4106.     fn->fn_Handle    = fh;
  4107.     fn->fn_FullName    = full_name;
  4108.     fn->fn_Mode        = (action == ACTION_FINDOUTPUT) ? EXCLUSIVE_LOCK : SHARED_LOCK;
  4109.  
  4110.     error = CheckAccessModeCollision(full_name,fn->fn_Mode);
  4111.     if(error != OK)
  4112.         goto out;
  4113.  
  4114.     SHOWSTRING(full_name);
  4115.  
  4116.     if(action == ACTION_FINDOUTPUT)
  4117.     {
  4118.         /* Definitely create a new file. */
  4119.         create_new_file = TRUE;
  4120.     }
  4121.     else if (action == ACTION_FINDINPUT)
  4122.     {
  4123.         /* Open an existing file for reading. */
  4124.         create_new_file = FALSE;
  4125.     }
  4126.     else if (action == ACTION_FINDUPDATE)
  4127.     {
  4128.         smba_file_t * file = NULL;
  4129.         smba_stat_t stat;
  4130.  
  4131.         if(smba_open(ServerData,full_name,&file) == OK &&
  4132.            smba_getattr(file,&stat) == OK)
  4133.         {
  4134.             /* File apparently opens Ok and information on it
  4135.              * is available, don't try to replace it.
  4136.              */
  4137.             create_new_file = FALSE;
  4138.         }
  4139.         else
  4140.         {
  4141.             /* We try to ignore the error here and assume
  4142.              * that the remainder of the file opening
  4143.              * procedure will produce a useful error
  4144.              * report. In the mean time, assume that the
  4145.              * file needs to be created.
  4146.              */
  4147.             create_new_file = TRUE;
  4148.         }
  4149.  
  4150.         if(file != NULL)
  4151.             smba_close(file);
  4152.     }
  4153.     else
  4154.     {
  4155.         /* What's that? */
  4156.         error = ERROR_ACTION_NOT_KNOWN;
  4157.         goto out;
  4158.     }
  4159.  
  4160.     /* Create a new file? */
  4161.     if(create_new_file)
  4162.     {
  4163.         smba_stat_t stat;
  4164.         smba_file_t * dir;
  4165.         STRPTR base_name;
  4166.         LONG i;
  4167.  
  4168.         if(WriteProtected)
  4169.         {
  4170.             error = ERROR_DISK_WRITE_PROTECTED;
  4171.             goto out;
  4172.         }
  4173.  
  4174.         parent_path = AllocVecPooled(strlen(full_name)+3);
  4175.         if(parent_path == NULL)
  4176.         {
  4177.             error = ERROR_NO_FREE_STORE;
  4178.             goto out;
  4179.         }
  4180.  
  4181.         strcpy(parent_path,full_name);
  4182.         base_name = NULL;
  4183.         for(i = strlen(parent_path)-1 ; i >= 0 ; i--)
  4184.         {
  4185.             if(i == 0)
  4186.             {
  4187.                 base_name = full_name;
  4188.                 strcpy(parent_path,SMB_ROOT_DIR_NAME);
  4189.                 break;
  4190.             }
  4191.             else if (parent_path[i] == SMB_PATH_SEPARATOR)
  4192.             {
  4193.                 base_name = &parent_path[i+1];
  4194.                 parent_path[i] = '\0';
  4195.                 break;
  4196.             }
  4197.         }
  4198.  
  4199.         SHOWMSG("creating a file; finding parent path first");
  4200.         SHOWSTRING(parent_path);
  4201.  
  4202.         error = smba_open(ServerData,parent_path,&dir);
  4203.         if(error < 0)
  4204.         {
  4205.             error = MapErrnoToIoErr(error);
  4206.             goto out;
  4207.         }
  4208.  
  4209.         /* Only one attribute counts: the file should not be write protected. */
  4210.         memset(&stat,0,sizeof(stat));
  4211.  
  4212.         SHOWMSG("now trying to create the file");
  4213.         SHOWSTRING(base_name);
  4214.  
  4215.         error = smba_create(dir,base_name,&stat);
  4216.         if(error < 0)
  4217.         {
  4218.             SHOWMSG("didn't work.");
  4219.             SHOWVALUE(error);
  4220.  
  4221.             smba_close(dir);
  4222.             error = MapErrnoToIoErr(error);
  4223.  
  4224.             SHOWVALUE(error);
  4225.  
  4226.             goto out;
  4227.         }
  4228.  
  4229.         SHOWMSG("good.");
  4230.  
  4231.         smba_close(dir);
  4232.     }
  4233.  
  4234.     /* Now for the remainder... */
  4235.     error = smba_open(ServerData,full_name,&fn->fn_File);
  4236.     if(error < 0)
  4237.     {
  4238.         error = MapErrnoToIoErr(error);
  4239.         goto out;
  4240.     }
  4241.  
  4242.     fh->fh_Arg1 = (LONG)fn;
  4243.  
  4244.     AddTail((struct List *)&FileList,(struct Node *)fn);
  4245.     result = DOSTRUE;
  4246.  
  4247.  out:
  4248.  
  4249.     if(result == DOSFALSE)
  4250.     {
  4251.         FreeVecPooled(full_name);
  4252.         FreeVecPooled(fn);
  4253.     }
  4254.  
  4255.     FreeVecPooled(parent_path);
  4256.  
  4257.     (*error_ptr) = error;
  4258.  
  4259.     RETURN(result);
  4260.     return(result);
  4261. }
  4262.  
  4263. /****************************************************************************/
  4264.  
  4265. STATIC LONG
  4266. Action_Read(
  4267.     struct FileNode *    fn,
  4268.     APTR                mem,
  4269.     LONG                length,
  4270.     LONG *                error_ptr)
  4271. {
  4272.     LONG result = 0;
  4273.     LONG error = OK;
  4274.  
  4275.     ENTER();
  4276.  
  4277.     if(length > 0)
  4278.     {
  4279.         result = smba_read(fn->fn_File,mem,length,fn->fn_Offset);
  4280.         if(result < 0)
  4281.         {
  4282.             error = MapErrnoToIoErr(result);
  4283.             result = -1;
  4284.             goto out;
  4285.         }
  4286.  
  4287.         fn->fn_Offset += result;
  4288.     }
  4289.  
  4290.  out:
  4291.  
  4292.     (*error_ptr) = error;
  4293.  
  4294.     RETURN(result);
  4295.     return(result);
  4296. }
  4297.  
  4298. /****************************************************************************/
  4299.  
  4300. STATIC LONG
  4301. Action_Write(
  4302.     struct FileNode *    fn,
  4303.     APTR                mem,
  4304.     LONG                length,
  4305.     LONG *                error_ptr)
  4306. {
  4307.     LONG result = DOSFALSE;
  4308.     LONG error = OK;
  4309.  
  4310.     ENTER();
  4311.  
  4312.     if(WriteProtected)
  4313.     {
  4314.         error = ERROR_DISK_WRITE_PROTECTED;
  4315.         goto out;
  4316.     }
  4317.  
  4318.     if(length > 0)
  4319.     {
  4320.         result = smba_write(fn->fn_File,mem,length,fn->fn_Offset);
  4321.         if(result < 0)
  4322.         {
  4323.             error = MapErrnoToIoErr(result);
  4324.             result = -1;
  4325.             goto out;
  4326.         }
  4327.  
  4328.         fn->fn_Offset += result;
  4329.     }
  4330.  
  4331.  out:
  4332.  
  4333.     (*error_ptr) = error;
  4334.  
  4335.     RETURN(result);
  4336.     return(result);
  4337. }
  4338.  
  4339. /****************************************************************************/
  4340.  
  4341. STATIC LONG
  4342. Action_End(
  4343.     struct FileNode *    fn,
  4344.     LONG *                error_ptr)
  4345. {
  4346.     Remove((struct Node *)fn);
  4347.  
  4348.     smba_close(fn->fn_File);
  4349.     FreeVecPooled(fn->fn_FullName);
  4350.     FreeVecPooled(fn);
  4351.  
  4352.     (*error_ptr) = OK;
  4353.     return(DOSTRUE);
  4354. }
  4355.  
  4356. /****************************************************************************/
  4357.  
  4358. STATIC LONG
  4359. Action_Seek(
  4360.     struct FileNode *    fn,
  4361.     LONG                position,
  4362.     LONG                mode,
  4363.     LONG *                error_ptr)
  4364. {
  4365.     smba_stat_t stat;
  4366.     LONG result;
  4367.     LONG error;
  4368.     LONG offset;
  4369.  
  4370.     ENTER();
  4371.  
  4372.     error = smba_getattr(fn->fn_File,&stat);
  4373.     if(error < 0)
  4374.     {
  4375.         error = MapErrnoToIoErr(error);
  4376.         result = -1;
  4377.         goto out;
  4378.     }
  4379.  
  4380.     result = offset = fn->fn_Offset;
  4381.  
  4382.     switch(mode)
  4383.     {
  4384.         case OFFSET_BEGINNING:
  4385.  
  4386.             offset = position;
  4387.             break;
  4388.  
  4389.         case OFFSET_CURRENT:
  4390.  
  4391.             offset += position;
  4392.             break;
  4393.  
  4394.         case OFFSET_END:
  4395.  
  4396.             offset = stat.size + position;
  4397.             break;
  4398.  
  4399.         default:
  4400.  
  4401.             error = ERROR_ACTION_NOT_KNOWN;
  4402.  
  4403.             result = -1;
  4404.             goto out;
  4405.     }
  4406.  
  4407.     if(offset < 0 || offset > stat.size)
  4408.     {
  4409.         error = ERROR_SEEK_ERROR;
  4410.  
  4411.         result = -1;
  4412.         goto out;
  4413.     }
  4414.  
  4415.     fn->fn_Offset = offset;
  4416.  
  4417.  out:
  4418.  
  4419.     (*error_ptr) = error;
  4420.  
  4421.     RETURN(result);
  4422.     return(result);
  4423. }
  4424.  
  4425. /****************************************************************************/
  4426.  
  4427. STATIC LONG
  4428. Action_SetFileSize(
  4429.     struct FileNode *    fn,
  4430.     LONG                position,
  4431.     LONG                mode,
  4432.     LONG *                error_ptr)
  4433. {
  4434.     smba_stat_t stat;
  4435.     LONG result = -1;
  4436.     LONG error;
  4437.     long offset;
  4438.  
  4439.     ENTER();
  4440.  
  4441.     if(WriteProtected)
  4442.     {
  4443.         error = ERROR_DISK_WRITE_PROTECTED;
  4444.         goto out;
  4445.     }
  4446.  
  4447.     error = smba_getattr(fn->fn_File,&stat);
  4448.     if(error < 0)
  4449.     {
  4450.         error = MapErrnoToIoErr(error);
  4451.         goto out;
  4452.     }
  4453.  
  4454.     offset = fn->fn_Offset;
  4455.  
  4456.     switch(mode)
  4457.     {
  4458.         case OFFSET_BEGINNING:
  4459.  
  4460.             offset = position;
  4461.             break;
  4462.  
  4463.         case OFFSET_CURRENT:
  4464.  
  4465.             offset += position;
  4466.             break;
  4467.  
  4468.         case OFFSET_END:
  4469.  
  4470.             offset = stat.size + position;
  4471.             break;
  4472.  
  4473.         default:
  4474.  
  4475.             error = ERROR_ACTION_NOT_KNOWN;
  4476.             goto out;
  4477.     }
  4478.  
  4479.     if(offset < 0)
  4480.     {
  4481.         error = ERROR_SEEK_ERROR;
  4482.         goto out;
  4483.     }
  4484.  
  4485.     stat.atime    = -1;
  4486.     stat.ctime    = -1;
  4487.     stat.mtime    = -1;
  4488.     stat.size    = offset;
  4489.  
  4490.     error = smba_setattr(fn->fn_File,&stat);
  4491.     if(error < 0)
  4492.     {
  4493.         error = MapErrnoToIoErr(error);
  4494.         goto out;
  4495.     }
  4496.  
  4497.     if(fn->fn_Offset > offset)
  4498.         fn->fn_Offset = offset;
  4499.  
  4500.     result = offset;
  4501.  
  4502.  out:
  4503.  
  4504.     (*error_ptr) = error;
  4505.  
  4506.     RETURN(result);
  4507.     return(result);
  4508. }
  4509.  
  4510. /****************************************************************************/
  4511.  
  4512. STATIC LONG
  4513. Action_SetDate(
  4514.     struct FileLock *    parent,
  4515.     APTR                bcpl_name,
  4516.     struct DateStamp *    ds,
  4517.     LONG *                error_ptr)
  4518. {
  4519.     LONG result = DOSFALSE;
  4520.     STRPTR full_name = NULL;
  4521.     smba_file_t * file = NULL;
  4522.     STRPTR parent_name;
  4523.     UBYTE name[MAX_FILENAME_LEN];
  4524.     smba_stat_t stat;
  4525.     LONG seconds;
  4526.     LONG error;
  4527.  
  4528.     ENTER();
  4529.  
  4530.     if(WriteProtected)
  4531.     {
  4532.         error = ERROR_DISK_WRITE_PROTECTED;
  4533.         goto out;
  4534.     }
  4535.  
  4536.     SHOWVALUE(parent);
  4537.  
  4538.     if(parent != NULL)
  4539.     {
  4540.         struct LockNode * ln = (struct LockNode *)parent->fl_Key;
  4541.  
  4542.         parent_name = ln->ln_FullName;
  4543.         if(strcmp(parent_name,SMB_ROOT_DIR_NAME) == SAME)
  4544.             parent_name = NULL;
  4545.     }
  4546.     else
  4547.     {
  4548.         parent_name = NULL;
  4549.     }
  4550.  
  4551.     ConvertBString(sizeof(name),name,bcpl_name);
  4552.     TranslateCName(name,A2M);
  4553.  
  4554.     error = BuildFullName(parent_name,name,&full_name);
  4555.     if(error != OK)
  4556.         goto out;
  4557.  
  4558.     SHOWSTRING(full_name);
  4559.  
  4560.     error = smba_open(ServerData,full_name,&file);
  4561.     if(error < 0)
  4562.     {
  4563.         error = MapErrnoToIoErr(error);
  4564.         goto out;
  4565.     }
  4566.  
  4567.     error = smba_getattr(file,&stat);
  4568.     if(error < 0)
  4569.     {
  4570.         error = MapErrnoToIoErr(error);
  4571.         goto out;
  4572.     }
  4573.  
  4574.     seconds = (ds->ds_Days * 24 * 60 + ds->ds_Minute) * 60 + (ds->ds_Tick / TICKS_PER_SECOND);
  4575.  
  4576.     stat.atime = -1;
  4577.     stat.ctime = -1;
  4578.     stat.mtime = UNIX_TIME_OFFSET + seconds + GetTimeZoneDelta();
  4579.     stat.size = -1;
  4580.  
  4581.     error = smba_setattr(file,&stat);
  4582.     if(error < 0)
  4583.     {
  4584.         error = MapErrnoToIoErr(error);
  4585.         goto out;
  4586.     }
  4587.  
  4588.     result = DOSTRUE;
  4589.  
  4590.  out:
  4591.  
  4592.     FreeVecPooled(full_name);
  4593.     if(file != NULL)
  4594.         smba_close(file);
  4595.  
  4596.     (*error_ptr) = error;
  4597.  
  4598.     RETURN(result);
  4599.     return(result);
  4600. }
  4601.  
  4602. /****************************************************************************/
  4603.  
  4604. STATIC LONG
  4605. Action_ExamineFH(
  4606.     struct FileNode *        fn,
  4607.     struct FileInfoBlock *    fib,
  4608.     LONG *                    error_ptr)
  4609. {
  4610.     LONG result = DOSFALSE;
  4611.     smba_stat_t stat;
  4612.     LONG error;
  4613.     LONG seconds;
  4614.     STRPTR name;
  4615.     LONG i;
  4616.  
  4617.     ENTER();
  4618.  
  4619.     error = smba_getattr(fn->fn_File,&stat);
  4620.     if(error < 0)
  4621.     {
  4622.         error = MapErrnoToIoErr(error);
  4623.         goto out;
  4624.     }
  4625.  
  4626.     name = fn->fn_FullName;
  4627.     for(i = strlen(name)-1 ; i >= 0 ; i--)
  4628.     {
  4629.         if(name[i] == SMB_PATH_SEPARATOR)
  4630.         {
  4631.             name = &name[i+1];
  4632.             break;
  4633.         }
  4634.     }
  4635.  
  4636.     /* Just checking: will the name fit? */
  4637.     if(strlen(name) >= sizeof(fib->fib_FileName))
  4638.     {
  4639.         error = ERROR_INVALID_COMPONENT_NAME;
  4640.         goto out;
  4641.     }
  4642.  
  4643.     memset(fib,0,sizeof(*fib));
  4644.  
  4645.     ConvertCString(sizeof(fib->fib_FileName),fib->fib_FileName,name);
  4646.     TranslateBName(fib->fib_FileName,M2A);
  4647.  
  4648.     fib->fib_DirEntryType    = ST_FILE;
  4649.     fib->fib_EntryType        = ST_FILE;
  4650.     fib->fib_NumBlocks        = (stat.size + 511) / 512;
  4651.     fib->fib_Size            = stat.size;
  4652.     fib->fib_DiskKey        = -1;
  4653.  
  4654.     seconds = stat.mtime - UNIX_TIME_OFFSET - GetTimeZoneDelta();
  4655.     if(seconds < 0)
  4656.         seconds = 0;
  4657.  
  4658.     fib->fib_Date.ds_Days    = (seconds / (24 * 60 * 60));
  4659.     fib->fib_Date.ds_Minute    = (seconds % (24 * 60 * 60)) / 60;
  4660.     fib->fib_Date.ds_Tick    = (seconds % 60) * TICKS_PER_SECOND;
  4661.  
  4662.     result = DOSTRUE;
  4663.  
  4664.  out:
  4665.  
  4666.     (*error_ptr) = error;
  4667.  
  4668.     RETURN(result);
  4669.     return(result);
  4670. }
  4671.  
  4672. /****************************************************************************/
  4673.  
  4674. STATIC BPTR
  4675. Action_ParentFH(
  4676.     struct FileNode *    fn,
  4677.     LONG *                error_ptr)
  4678. {
  4679.     BPTR result = ZERO;
  4680.     struct LockNode * ln = NULL;
  4681.     LONG error;
  4682.     STRPTR full_name;
  4683.     LONG i;
  4684.  
  4685.     ENTER();
  4686.  
  4687.     full_name = AllocVecPooled(strlen(fn->fn_FullName)+3);
  4688.     if(full_name == NULL)
  4689.     {
  4690.         error = ERROR_NO_FREE_STORE;
  4691.         goto out;
  4692.     }
  4693.  
  4694.     strcpy(full_name,fn->fn_FullName);
  4695.  
  4696.     for(i = strlen(full_name)-1 ; i >= 0 ; i--)
  4697.     {
  4698.         if(i == 0)
  4699.         {
  4700.             strcpy(full_name,SMB_ROOT_DIR_NAME);
  4701.             break;
  4702.         }
  4703.         else if (full_name[i] == SMB_PATH_SEPARATOR)
  4704.         {
  4705.             full_name[i] = '\0';
  4706.             break;
  4707.         }
  4708.     }
  4709.  
  4710.     ln = AllocVecPooled(sizeof(*ln));
  4711.     if(ln == NULL)
  4712.     {
  4713.         error = ERROR_NO_FREE_STORE;
  4714.         goto out;
  4715.     }
  4716.  
  4717.     memset(ln,0,sizeof(*ln));
  4718.  
  4719.     ln->ln_FileLock.fl_Key        = (LONG)ln;
  4720.     ln->ln_FileLock.fl_Access    = SHARED_LOCK;
  4721.     ln->ln_FileLock.fl_Task        = FileSystemPort;
  4722.     ln->ln_FileLock.fl_Volume    = MKBADDR(VolumeNode);
  4723.     ln->ln_FullName                = full_name;
  4724.  
  4725.     SHOWSTRING(full_name);
  4726.  
  4727.     error = smba_open(ServerData,full_name,&ln->ln_File);
  4728.     if(error < 0)
  4729.     {
  4730.         error = MapErrnoToIoErr(error);
  4731.         goto out;
  4732.     }
  4733.  
  4734.     AddTail((struct List *)&LockList,(struct Node *)ln);
  4735.     result = MKBADDR(&ln->ln_FileLock);
  4736.     SHOWVALUE(&ln->ln_FileLock);
  4737.  
  4738.  out:
  4739.  
  4740.     if(result == ZERO)
  4741.     {
  4742.         FreeVecPooled(ln);
  4743.         FreeVecPooled(full_name);
  4744.     }
  4745.  
  4746.     (*error_ptr) = error;
  4747.  
  4748.     RETURN(result);
  4749.     return(result);
  4750. }
  4751.  
  4752. /****************************************************************************/
  4753.  
  4754. STATIC BPTR
  4755. Action_CopyDirFH(
  4756.     struct FileNode *    fn,
  4757.     LONG *                error_ptr)
  4758. {
  4759.     BPTR result = ZERO;
  4760.     struct LockNode * ln = NULL;
  4761.     STRPTR full_name = NULL;
  4762.     LONG error;
  4763.  
  4764.     ENTER();
  4765.  
  4766.     if(fn->fn_Mode != SHARED_LOCK)
  4767.     {
  4768.         error = ERROR_OBJECT_IN_USE;
  4769.         goto out;
  4770.     }
  4771.  
  4772.     full_name = AllocVecPooled(strlen(fn->fn_FullName)+3);
  4773.     if(full_name == NULL)
  4774.     {
  4775.         error = ERROR_NO_FREE_STORE;
  4776.         goto out;
  4777.     }
  4778.  
  4779.     strcpy(full_name,fn->fn_FullName);
  4780.  
  4781.     ln = AllocVecPooled(sizeof(*ln));
  4782.     if(ln == NULL)
  4783.     {
  4784.         error = ERROR_NO_FREE_STORE;
  4785.         goto out;
  4786.     }
  4787.  
  4788.     memset(ln,0,sizeof(*ln));
  4789.  
  4790.     ln->ln_FileLock.fl_Key        = (LONG)ln;
  4791.     ln->ln_FileLock.fl_Access    = SHARED_LOCK;
  4792.     ln->ln_FileLock.fl_Task        = FileSystemPort;
  4793.     ln->ln_FileLock.fl_Volume    = MKBADDR(VolumeNode);
  4794.     ln->ln_FullName                = full_name;
  4795.  
  4796.     SHOWSTRING(full_name);
  4797.  
  4798.     error = smba_open(ServerData,full_name,&ln->ln_File);
  4799.     if(error < 0)
  4800.     {
  4801.         error = MapErrnoToIoErr(error);
  4802.         goto out;
  4803.     }
  4804.  
  4805.     AddTail((struct List *)&LockList,(struct Node *)ln);
  4806.     result = MKBADDR(&ln->ln_FileLock);
  4807.     SHOWVALUE(&ln->ln_FileLock);
  4808.  
  4809.  out:
  4810.  
  4811.     if(result == ZERO)
  4812.     {
  4813.         FreeVecPooled(ln);
  4814.         FreeVecPooled(full_name);
  4815.     }
  4816.  
  4817.     (*error_ptr) = error;
  4818.  
  4819.     RETURN(result);
  4820.     return(result);
  4821. }
  4822.  
  4823. /****************************************************************************/
  4824.  
  4825. STATIC LONG
  4826. Action_FHFromLock(
  4827.     struct FileHandle *    fh,
  4828.     struct FileLock *    fl,
  4829.     LONG *                error_ptr)
  4830. {
  4831.     LONG result = DOSFALSE;
  4832.     struct FileNode * fn;
  4833.     struct LockNode * ln;
  4834.     LONG error = OK;
  4835.  
  4836.     ENTER();
  4837.  
  4838.     SHOWVALUE(fl);
  4839.  
  4840.     fn = AllocVecPooled(sizeof(*fn));
  4841.     if(fn == NULL)
  4842.     {
  4843.         error = ERROR_NO_FREE_STORE;
  4844.         goto out;
  4845.     }
  4846.  
  4847.     memset(fn,0,sizeof(*fn));
  4848.  
  4849.     ln = (struct LockNode *)fl->fl_Key;
  4850.  
  4851.     fn->fn_Handle    = fh;
  4852.     fn->fn_FullName    = ln->ln_FullName;
  4853.     fn->fn_File        = ln->ln_File;
  4854.     fn->fn_Mode        = fl->fl_Access;
  4855.  
  4856.     Remove((struct Node *)ln);
  4857.     FreeVecPooled(ln);
  4858.  
  4859.     fh->fh_Arg1 = (LONG)fn;
  4860.  
  4861.     AddTail((struct List *)&FileList,(struct Node *)fn);
  4862.     result = DOSTRUE;
  4863.  
  4864.  out:
  4865.  
  4866.     (*error_ptr) = error;
  4867.  
  4868.     RETURN(result);
  4869.     return(result);
  4870. }
  4871.  
  4872. /****************************************************************************/
  4873.  
  4874. STATIC LONG
  4875. Action_RenameDisk(
  4876.     APTR    bcpl_name,
  4877.     LONG *    error_ptr)
  4878. {
  4879.     LONG result = DOSFALSE;
  4880.     LONG error = OK;
  4881.     STRPTR old_name;
  4882.     STRPTR new_name;
  4883.     UBYTE * name;
  4884.     LONG len;
  4885.  
  4886.     ENTER();
  4887.  
  4888.     if(NOT VolumeNodeAdded)
  4889.     {
  4890.         error = ERROR_OBJECT_IN_USE;
  4891.         goto out;
  4892.     }
  4893.  
  4894.     if(WriteProtected)
  4895.     {
  4896.         error = ERROR_DISK_WRITE_PROTECTED;
  4897.         goto out;
  4898.     }
  4899.  
  4900.     /* Now for the really interesting part; the new name
  4901.      * is to be a NUL-terminated BCPL string, and as such
  4902.      * must be allocated via AllocVec().
  4903.      */
  4904.  
  4905.     name = bcpl_name;
  4906.  
  4907.     len = name[0];
  4908.  
  4909.     new_name = AllocVec(1 + len + 1,MEMF_ANY|MEMF_PUBLIC);
  4910.     if(new_name == NULL)
  4911.     {
  4912.         error = ERROR_NO_FREE_STORE;
  4913.         goto out;
  4914.     }
  4915.  
  4916.     new_name[0] = len;
  4917.     memcpy(&new_name[1],&name[1],len);
  4918.     new_name[len+1] = '\0';
  4919.  
  4920.     Forbid();
  4921.  
  4922.     old_name = BADDR(VolumeNode->dol_Name);
  4923.     FreeVec(old_name);
  4924.     VolumeNode->dol_Name = MKBADDR(new_name);
  4925.  
  4926.     Permit();
  4927.  
  4928.     SendDiskChange(IECLASS_DISKINSERTED);
  4929.  
  4930.     result = DOSTRUE;
  4931.  
  4932.  out:
  4933.  
  4934.     (*error_ptr) = error;
  4935.  
  4936.     RETURN(result);
  4937.     return(result);
  4938. }
  4939.  
  4940. /****************************************************************************/
  4941.  
  4942. STATIC LONG
  4943. Action_ChangeMode(
  4944.     LONG                type,
  4945.     APTR                object,
  4946.     LONG                new_mode,
  4947.     LONG *                error_ptr)
  4948. {
  4949.     LONG result = DOSFALSE;
  4950.     struct FileLock * fl = NULL;
  4951.     struct FileNode * fn = NULL;
  4952.     struct LockNode * ln = NULL;
  4953.     STRPTR name;
  4954.     LONG old_mode;
  4955.     LONG error = OK;
  4956.  
  4957.     ENTER();
  4958.  
  4959.     /* Sanity check; verify parameters */
  4960.     if((type != CHANGE_LOCK && type != CHANGE_FH) ||
  4961.        (new_mode != EXCLUSIVE_LOCK && new_mode != SHARED_LOCK))
  4962.     {
  4963.         error = ERROR_ACTION_NOT_KNOWN;
  4964.         goto out;
  4965.     }
  4966.  
  4967.     /* Now obtain the data structures, name and mode
  4968.      * associated with the object in question.
  4969.      */
  4970.     if(type == CHANGE_LOCK)
  4971.     {
  4972.         fl = object;
  4973.         ln = (struct LockNode *)fl->fl_Key;
  4974.         name = ln->ln_FullName;
  4975.         old_mode = fl->fl_Access;
  4976.     }
  4977.     else
  4978.     {
  4979.         struct FileHandle * fh = object;
  4980.  
  4981.         fn = (struct FileNode *)fh->fh_Arg1;
  4982.         name = fn->fn_FullName;
  4983.         old_mode = fn->fn_Mode;
  4984.     }
  4985.  
  4986.     /* Do we need to change anything at all? */
  4987.     if(new_mode == old_mode)
  4988.     {
  4989.         result = DOSTRUE;
  4990.         goto out;
  4991.     }
  4992.  
  4993.     /* This is the easiest case; change an
  4994.      * exclusive access mode to a shared
  4995.      * access mode. Since the original mode
  4996.      * can be used by one object only,
  4997.      * we get away by updating the mode
  4998.      * value.
  4999.      */
  5000.     if(new_mode == SHARED_LOCK)
  5001.     {
  5002.         if(type == CHANGE_LOCK)
  5003.             fl->fl_Access = new_mode;
  5004.         else
  5005.             fn->fn_Mode = new_mode;
  5006.  
  5007.         result = DOSTRUE;
  5008.         goto out;
  5009.     }
  5010.  
  5011.     /* Is there another shared access lock
  5012.      * which refers to the same object?
  5013.      */
  5014.     if(FindLockNode(name,ln) != NULL)
  5015.     {
  5016.         error = ERROR_OBJECT_IN_USE;
  5017.         goto out;
  5018.     }
  5019.  
  5020.     /* Is there another shared access file
  5021.      * which refers to the same object?
  5022.      */
  5023.     if(FindFileNode(name,fn) != NULL)
  5024.     {
  5025.         error = ERROR_OBJECT_IN_USE;
  5026.         goto out;
  5027.     }
  5028.  
  5029.     /* There is just one single reference
  5030.      * to this object; change the mode
  5031.      * and quit.
  5032.      */
  5033.     if(type == CHANGE_LOCK)
  5034.         fl->fl_Access = new_mode;
  5035.     else
  5036.         fn->fn_Mode = new_mode;
  5037.  
  5038.     result = DOSTRUE;
  5039.  
  5040.  out:
  5041.  
  5042.     (*error_ptr) = error;
  5043.  
  5044.     RETURN(result);
  5045.     return(result);
  5046. }
  5047.  
  5048. /****************************************************************************/
  5049.  
  5050. STATIC LONG
  5051. Action_WriteProtect(
  5052.     LONG    flag,
  5053.     ULONG    key,
  5054.     LONG *    error_ptr)
  5055. {
  5056.     LONG result = DOSFALSE;
  5057.     LONG error = OK;
  5058.  
  5059.     ENTER();
  5060.  
  5061.     if(flag == DOSFALSE)
  5062.     {
  5063.         if(WriteProtected)
  5064.         {
  5065.             if(key != WriteProtectKey)
  5066.             {
  5067.                 error = ERROR_INVALID_LOCK;
  5068.                 goto out;
  5069.             }
  5070.  
  5071.             WriteProtected = FALSE;
  5072.  
  5073.             if(VolumeNodeAdded)
  5074.             {
  5075.                 SendDiskChange(IECLASS_DISKREMOVED);
  5076.                 SendDiskChange(IECLASS_DISKINSERTED);
  5077.             }
  5078.         }
  5079.     }
  5080.     else
  5081.     {
  5082.         if(NOT WriteProtected)
  5083.         {
  5084.             WriteProtected = TRUE;
  5085.             WriteProtectKey = key;
  5086.  
  5087.             if(VolumeNodeAdded)
  5088.             {
  5089.                 SendDiskChange(IECLASS_DISKREMOVED);
  5090.                 SendDiskChange(IECLASS_DISKINSERTED);
  5091.             }
  5092.         }
  5093.         else
  5094.         {
  5095.             error = ERROR_INVALID_LOCK;
  5096.             goto out;
  5097.         }
  5098.     }
  5099.  
  5100.     result = DOSTRUE;
  5101.  
  5102.  out:
  5103.  
  5104.     (*error_ptr) = error;
  5105.  
  5106.     RETURN(result);
  5107.     return(result);
  5108. }
  5109.  
  5110. /****************************************************************************/
  5111.  
  5112. STATIC LONG
  5113. Action_MoreCache(
  5114.     LONG    buffer_delta,
  5115.     LONG *    error_ptr)
  5116. {
  5117.     LONG result;
  5118.     int old_size;
  5119.  
  5120.     ENTER();
  5121.  
  5122.     old_size = smba_get_dircache_size(ServerData);
  5123.  
  5124.     result = smba_change_dircache_size(ServerData,old_size + buffer_delta);
  5125.  
  5126.     if(result == old_size && buffer_delta != 0)
  5127.     {
  5128.         result = DOSFALSE;
  5129.         (*error_ptr) = ERROR_NO_FREE_STORE;
  5130.     }
  5131.  
  5132.     RETURN(result);
  5133.     return(result);
  5134. }
  5135.  
  5136. /****************************************************************************/
  5137.  
  5138. STATIC LONG
  5139. Action_SetComment(
  5140.     struct FileLock *    parent,
  5141.     APTR                bcpl_name,
  5142.     APTR                bcpl_comment,
  5143.     LONG *                error_ptr)
  5144. {
  5145.     LONG result = DOSFALSE;
  5146.     STRPTR full_name = NULL;
  5147.     smba_file_t * file = NULL;
  5148.     STRPTR parent_name;
  5149.     UBYTE name[MAX_FILENAME_LEN];
  5150.     UBYTE comment[80];
  5151.     LONG error;
  5152.  
  5153.     ENTER();
  5154.  
  5155.     if(WriteProtected)
  5156.     {
  5157.         error = ERROR_DISK_WRITE_PROTECTED;
  5158.         goto out;
  5159.     }
  5160.  
  5161.     SHOWVALUE(parent);
  5162.  
  5163.     if(parent != NULL)
  5164.     {
  5165.         struct LockNode * ln = (struct LockNode *)parent->fl_Key;
  5166.  
  5167.         parent_name = ln->ln_FullName;
  5168.         if(strcmp(parent_name,SMB_ROOT_DIR_NAME) == SAME)
  5169.             parent_name = NULL;
  5170.     }
  5171.     else
  5172.     {
  5173.         parent_name = NULL;
  5174.     }
  5175.  
  5176.     ConvertBString(sizeof(name),name,bcpl_name);
  5177.     TranslateCName(name,A2M);
  5178.  
  5179.     error = BuildFullName(parent_name,name,&full_name);
  5180.     if(error != OK)
  5181.         goto out;
  5182.  
  5183.     SHOWSTRING(full_name);
  5184.  
  5185.     error = smba_open(ServerData,full_name,&file);
  5186.     if(error < 0)
  5187.     {
  5188.         error = MapErrnoToIoErr(error);
  5189.         goto out;
  5190.     }
  5191.  
  5192.     ConvertBString(sizeof(comment),comment,bcpl_comment);
  5193.  
  5194.     SHOWSTRING(comment);
  5195.  
  5196.     /* All this work and we're only doing something very silly... */
  5197.     if(strlen(comment) > 0)
  5198.     {
  5199.         error = ERROR_COMMENT_TOO_BIG;
  5200.         goto out;
  5201.     }
  5202.  
  5203.     result = DOSTRUE;
  5204.  
  5205.  out:
  5206.  
  5207.     FreeVecPooled(full_name);
  5208.     if(file != NULL)
  5209.         smba_close(file);
  5210.  
  5211.     (*error_ptr) = error;
  5212.  
  5213.     RETURN(result);
  5214.     return(result);
  5215. }
  5216.  
  5217. /****************************************************************************/
  5218.  
  5219. STATIC VOID
  5220. HandleFileSystem(STRPTR device_name,STRPTR volume_name,STRPTR service_name)
  5221. {
  5222.     BOOL sign_off = FALSE;
  5223.     ULONG signals;
  5224.     BOOL done;
  5225.  
  5226.     ENTER();
  5227.  
  5228.     DisplayErrorList();
  5229.  
  5230.     if(NOT Quiet && WBStartup == NULL)
  5231.     {
  5232.         struct CommandLineInterface * cli;
  5233.  
  5234.         cli = Cli();
  5235.         if(NOT cli->cli_Background)
  5236.         {
  5237.             struct Process * this_process;
  5238.             UBYTE name[MAX_FILENAME_LEN];
  5239.             LONG max_cli;
  5240.             LONG which;
  5241.             LONG i;
  5242.  
  5243.             this_process = (struct Process *)FindTask(NULL);
  5244.  
  5245.             Forbid();
  5246.  
  5247.             which = max_cli = MaxCli();
  5248.  
  5249.             for(i = 1 ; i <= max_cli ; i++)
  5250.             {
  5251.                 if(FindCliProc(i) == this_process)
  5252.                 {
  5253.                     which = i;
  5254.                     break;
  5255.                 }
  5256.             }
  5257.  
  5258.             Permit();
  5259.  
  5260.             if(volume_name == NULL)
  5261.                 strncpy(name,device_name,sizeof(name)-1);
  5262.             else
  5263.                 strncpy(name,volume_name,sizeof(name)-1);
  5264.  
  5265.             name[sizeof(name)-1] = '\0';
  5266.  
  5267.             for(i = strlen(name)-1 ; i >= 0 ; i--)
  5268.             {
  5269.                 if(name[i] == ':')
  5270.                     name[i] = '\0';
  5271.                 else
  5272.                     break;
  5273.             }
  5274.  
  5275.             Printf("Connected '%s' to '%s:'; \"Break %ld\" or [Ctrl-C] to stop... ",
  5276.             service_name,name,which);
  5277.  
  5278.             Flush(Output());
  5279.  
  5280.             sign_off = TRUE;
  5281.         }
  5282.     }
  5283.  
  5284.     Quiet = TRUE;
  5285.  
  5286.     done = FALSE;
  5287.  
  5288.     do
  5289.     {
  5290.         signals = Wait(SIGBREAKF_CTRL_C | SIGBREAKF_CTRL_F | (1UL << FileSystemPort->mp_SigBit));
  5291.  
  5292.         if(signals & (1UL << FileSystemPort->mp_SigBit))
  5293.         {
  5294.             struct DosPacket * dp;
  5295.             struct Message * mn;
  5296.             LONG res1,res2;
  5297.  
  5298.             while((mn = GetMsg(FileSystemPort)) != NULL)
  5299.             {
  5300.                 dp = (struct DosPacket *)mn->mn_Node.ln_Name;
  5301.  
  5302.                 D(("got packet; sender '%s'",((struct Node *)dp->dp_Port->mp_SigTask)->ln_Name));
  5303.  
  5304.                 res2 = 0;
  5305.  
  5306.                 switch(dp->dp_Action)
  5307.                 {
  5308.                     case ACTION_DIE:
  5309.  
  5310.                         SHOWMSG("ACTION_DIE");
  5311.                         if(IsListEmpty((struct List *)&FileList) && IsListEmpty((struct List *)&LockList))
  5312.                         {
  5313.                             SHOWMSG("no locks or files pending; quitting");
  5314.  
  5315.                             res1 = DOSTRUE;
  5316.                         }
  5317.                         else
  5318.                         {
  5319.                             SHOWMSG("locks or files still pending; cannot quit yet");
  5320.  
  5321.                             res1 = DOSFALSE;
  5322.                             res2 = ERROR_OBJECT_IN_USE;
  5323.  
  5324.                             Quit = TRUE;
  5325.                         }
  5326.  
  5327.                         break;
  5328.  
  5329.                     case ACTION_CURRENT_VOLUME:
  5330.                         /* (Ignore) -> VolumeNode */
  5331.  
  5332.                         res1 = MKBADDR(VolumeNode);
  5333.                         break;
  5334.  
  5335.                     case ACTION_LOCATE_OBJECT:
  5336.                         /* Lock,Name,Mode -> Lock */
  5337.  
  5338.                         res1 = Action_LocateObject((struct FileLock *)BADDR(dp->dp_Arg1),(APTR)BADDR(dp->dp_Arg2),dp->dp_Arg3,&res2);
  5339.                         break;
  5340.  
  5341.                     case ACTION_RENAME_DISK:
  5342.                         /* Name -> Bool */
  5343.  
  5344.                         res1 = Action_RenameDisk((UBYTE *)BADDR(dp->dp_Arg1),&res2);
  5345.                         break;
  5346.  
  5347.                     case ACTION_FREE_LOCK:
  5348.                         /* Lock -> Bool */
  5349.  
  5350.                         res1 = Action_FreeLock((struct FileLock *)BADDR(dp->dp_Arg1),&res2);
  5351.                         break;
  5352.  
  5353.                     case ACTION_DELETE_OBJECT:
  5354.                         /* Lock,Name -> Bool */
  5355.  
  5356.                         res1 = Action_DeleteObject((struct FileLock *)BADDR(dp->dp_Arg1),(APTR)BADDR(dp->dp_Arg2),&res2);
  5357.                         break;
  5358.  
  5359.                     case ACTION_RENAME_OBJECT:
  5360.                         /* Source lock,source name,destination lock,destination name -> Bool */
  5361.  
  5362.                         res1 = Action_RenameObject((struct FileLock *)BADDR(dp->dp_Arg1),BADDR(dp->dp_Arg2),
  5363.                             (struct FileLock *)BADDR(dp->dp_Arg3),BADDR(dp->dp_Arg4),&res2);
  5364.  
  5365.                         break;
  5366.  
  5367.                     case ACTION_MORE_CACHE:
  5368.                         /* Buffer delta -> Total number of buffers */
  5369.  
  5370.                         /* NOTE: documentation for this packet type is inconsistent;
  5371.                          *       in the 'good old' 1.x days 'res1' was documented as
  5372.                          *       the total number of buffers to be returned. In the
  5373.                          *       2.x documentation it is said that 'res1' should
  5374.                          *       return the success code, with 'res2' to hold the
  5375.                          *       total number of buffers. However, the 'AddBuffers'
  5376.                          *       shell command doesn't work that way, and the
  5377.                          *       dos.library implementation of 'AddBuffers()' doesn't
  5378.                          *       work that way either. The 1.3 'AddBuffers' command
  5379.                          *       appears to treat a zero result as failure and a
  5380.                          *       non-zero result as success, which suggests that this
  5381.                          *       is how the packet is supposed to work, contrary to
  5382.                          *       what the official documentation says.
  5383.                          */
  5384.                         res1 = Action_MoreCache(dp->dp_Arg1,&res2);
  5385.                         break;
  5386.  
  5387.                     case ACTION_COPY_DIR:
  5388.                         /* Lock -> Lock */
  5389.  
  5390.                         res1 = Action_CopyDir((struct FileLock *)BADDR(dp->dp_Arg1),&res2);
  5391.                         break;
  5392.  
  5393.                     case ACTION_SET_PROTECT:
  5394.                         /* (Ignore),Lock,Name,Mask -> Bool */
  5395.  
  5396.                         res1 = Action_SetProtect((struct FileLock *)BADDR(dp->dp_Arg2),BADDR(dp->dp_Arg3),dp->dp_Arg4,&res2);
  5397.                         break;
  5398.  
  5399.                     case ACTION_CREATE_DIR:
  5400.                         /* Lock,Name -> Lock */
  5401.  
  5402.                         res1 = Action_CreateDir((struct FileLock *)BADDR(dp->dp_Arg1),(APTR)BADDR(dp->dp_Arg2),&res2);
  5403.                         break;
  5404.  
  5405.                     case ACTION_EXAMINE_OBJECT:
  5406.                         /* FileLock,FileInfoBlock -> Bool */
  5407.  
  5408.                         res1 = Action_ExamineObject((struct FileLock *)BADDR(dp->dp_Arg1),(struct FileInfoBlock *)BADDR(dp->dp_Arg2),&res2);
  5409.                         break;
  5410.  
  5411.                     case ACTION_EXAMINE_NEXT:
  5412.                         /* FileLock,FileInfoBlock -> Bool */
  5413.  
  5414.                         res1 = Action_ExamineNext((struct FileLock *)BADDR(dp->dp_Arg1),(struct FileInfoBlock *)BADDR(dp->dp_Arg2),&res2);
  5415.                         break;
  5416.  
  5417.                     case ACTION_DISK_INFO:
  5418.                         /* InfoData -> Bool */
  5419.  
  5420.                         Action_DiskInfo((struct InfoData *)BADDR(dp->dp_Arg1),&res2);
  5421.                         res1 = DOSTRUE;
  5422.                         res2 = 0;
  5423.                         break;
  5424.  
  5425.                     case ACTION_INFO:
  5426.                         /* FileLock,InfoData -> Bool */
  5427.  
  5428.                         res1 = Action_Info((struct FileLock *)BADDR(dp->dp_Arg1),(struct InfoData *)BADDR(dp->dp_Arg2),&res2);
  5429.                         break;
  5430.  
  5431.                     case ACTION_SET_COMMENT:
  5432.                         /* (Ignore),FileLock,Name,Comment -> Bool */
  5433.  
  5434.                         res1 = Action_SetComment((struct FileLock *)BADDR(dp->dp_Arg2),BADDR(dp->dp_Arg3),BADDR(dp->dp_Arg4),&res2);
  5435.                         break;
  5436.  
  5437.                     case ACTION_PARENT:
  5438.                         /* Lock -> Lock */
  5439.  
  5440.                         res1 = Action_Parent((struct FileLock *)BADDR(dp->dp_Arg1),&res2);
  5441.                         break;
  5442.  
  5443.                     case ACTION_INHIBIT:
  5444.  
  5445.                         SHOWMSG("ACTION_INHIBIT");
  5446.                         res1 = DOSTRUE;
  5447.                         break;
  5448.  
  5449.                     case ACTION_SET_DATE:
  5450.                         /* (Ignore),FileLock,Name,DateStamp(APTR) -> Bool */
  5451.  
  5452.                         res1 = Action_SetDate((struct FileLock *)BADDR(dp->dp_Arg2),(APTR)BADDR(dp->dp_Arg3),(struct DateStamp *)dp->dp_Arg4,&res2);
  5453.                         break;
  5454.  
  5455.                     case ACTION_SAME_LOCK:
  5456.                         /* Lock,Lock -> Bool */
  5457.  
  5458.                         res1 = Action_SameLock((struct FileLock *)BADDR(dp->dp_Arg1),(struct FileLock *)BADDR(dp->dp_Arg2),&res2);
  5459.                         break;
  5460.  
  5461.                     case ACTION_READ:
  5462.                         /* FileHandle->fh_Arg1,Buffer(APTR),Length -> Length */
  5463.  
  5464.                         res1 = Action_Read((struct FileNode *)dp->dp_Arg1,(APTR)dp->dp_Arg2,dp->dp_Arg3,&res2);
  5465.                         break;
  5466.  
  5467.                     case ACTION_WRITE:
  5468.                         /* FileHandle->fh_Arg1,Buffer(APTR),Length -> Length */
  5469.  
  5470.                         res1 = Action_Write((struct FileNode *)dp->dp_Arg1,(APTR)dp->dp_Arg2,dp->dp_Arg3,&res2);
  5471.                         break;
  5472.  
  5473.                     case ACTION_FINDUPDATE:
  5474.                     case ACTION_FINDINPUT:
  5475.                     case ACTION_FINDOUTPUT:
  5476.                         /* FileHandle,FileLock,Name -> Bool */
  5477.  
  5478.                         res1 = Action_Find(dp->dp_Action,(struct FileHandle *)BADDR(dp->dp_Arg1),(struct FileLock *)BADDR(dp->dp_Arg2),(APTR)BADDR(dp->dp_Arg3),&res2);
  5479.                         break;
  5480.  
  5481.                     case ACTION_END:
  5482.                         /* FileHandle->fh_Arg1 -> Bool */
  5483.  
  5484.                         res1 = Action_End((struct FileNode *)dp->dp_Arg1,&res2);
  5485.                         break;
  5486.  
  5487.                     case ACTION_SEEK:
  5488.                         /* FileHandle->fh_Arg1,Position,Mode -> Position */
  5489.  
  5490.                         res1 = Action_Seek((struct FileNode *)dp->dp_Arg1,dp->dp_Arg2,dp->dp_Arg3,&res2);
  5491.                         break;
  5492.  
  5493.                     case ACTION_SET_FILE_SIZE:
  5494.                         /* FileHandle->fh_Arg1,Offset,Mode -> New file size */
  5495.  
  5496.                         res1 = Action_SetFileSize((struct FileNode *)dp->dp_Arg1,dp->dp_Arg2,dp->dp_Arg3,&res2);
  5497.                         break;
  5498.  
  5499.                     case ACTION_WRITE_PROTECT:
  5500.                         /* Flag,Key -> Bool */
  5501.  
  5502.                         res1 = Action_WriteProtect(dp->dp_Arg1,dp->dp_Arg2,&res2);
  5503.                         break;
  5504.  
  5505.                     case ACTION_FH_FROM_LOCK:
  5506.                         /* FileHandle(BPTR),FileLock -> Bool */
  5507.  
  5508.                         res1 = Action_FHFromLock((struct FileHandle *)BADDR(dp->dp_Arg1),(struct FileLock *)BADDR(dp->dp_Arg2),&res2);
  5509.                         break;
  5510.  
  5511.                     case ACTION_IS_FILESYSTEM:
  5512.  
  5513.                         SHOWMSG("ACTION_IS_FILESYSTEM");
  5514.                         res1 = DOSTRUE;
  5515.                         break;
  5516.  
  5517.                     case ACTION_CHANGE_MODE:
  5518.                         /* Type,Object,Mode -> Bool */
  5519.  
  5520.                         res1 = Action_ChangeMode(dp->dp_Arg1,(APTR)BADDR(dp->dp_Arg2),dp->dp_Arg3,&res2);
  5521.                         break;
  5522.  
  5523.                     case ACTION_COPY_DIR_FH:
  5524.                         /* FileHandle->fh_Arg1 -> Bool */
  5525.  
  5526.                         res1 = Action_CopyDirFH((struct FileNode *)dp->dp_Arg1,&res2);
  5527.                         break;
  5528.  
  5529.                     case ACTION_PARENT_FH:
  5530.                         /* FileHandle->fh_Arg1 -> Bool */
  5531.  
  5532.                         res1 = Action_ParentFH((struct FileNode *)dp->dp_Arg1,&res2);
  5533.                         break;
  5534.  
  5535.                     case ACTION_EXAMINE_ALL:
  5536.                         /* FileLock,ExAllData(APTR),Size,Type,ExAllControl(APTR) -> Bool */
  5537.  
  5538.                         res1 = Action_ExamineAll((struct FileLock *)BADDR(dp->dp_Arg1),(struct ExAllData *)dp->dp_Arg2,
  5539.                             dp->dp_Arg3,dp->dp_Arg4,(struct ExAllControl *)dp->dp_Arg5,&res2);
  5540.  
  5541.                         break;
  5542.  
  5543.                     case ACTION_EXAMINE_FH:
  5544.                         /* FileHandle->fh_Arg1,FileInfoBlock -> Bool */
  5545.  
  5546.                         res1 = Action_ExamineFH((struct FileNode *)dp->dp_Arg1,(struct FileInfoBlock *)BADDR(dp->dp_Arg2),&res2);
  5547.                         break;
  5548.  
  5549.                     case ACTION_EXAMINE_ALL_END:
  5550.                         /* FileLock,ExAllData(APTR),Size,Type,ExAllControl(APTR) -> Bool */
  5551.  
  5552.                         res1 = DOSTRUE;
  5553.                         break;
  5554.  
  5555.                     default:
  5556.  
  5557.                         D(("Anything goes: dp->dp_Action=%ld (0x%lx)",dp->dp_Action,dp->dp_Action));
  5558.  
  5559.                         res1 = DOSFALSE;
  5560.                         res2 = ERROR_ACTION_NOT_KNOWN;
  5561.  
  5562.                         break;
  5563.                 }
  5564.  
  5565.                 SHOWVALUE(res1);
  5566.                 SHOWVALUE(res2);
  5567.  
  5568.                 ReplyPkt(dp,res1,res2);
  5569.  
  5570.                 D(("\n"));
  5571.             }
  5572.         }
  5573.  
  5574.         #if DEBUG
  5575.         {
  5576.             if(signals & SIGBREAKF_CTRL_F)
  5577.             {
  5578.                 struct FileNode * fn;
  5579.                 struct LockNode * ln;
  5580.  
  5581.                 D(("list of open files:"));
  5582.  
  5583.                 for(fn = (struct FileNode *)FileList.mlh_Head ;
  5584.                     fn->fn_MinNode.mln_Succ != NULL ;
  5585.                     fn = (struct FileNode *)fn->fn_MinNode.mln_Succ)
  5586.                 {
  5587.                     D(("  name='%s'",fn->fn_FullName));
  5588.                     D(("  mode=%ld, offset=%ld",fn->fn_Mode,fn->fn_Offset));
  5589.                     D((""));
  5590.                 }
  5591.  
  5592.                 D(("list of allocated locks:"));
  5593.  
  5594.                 for(ln = (struct LockNode *)LockList.mlh_Head ;
  5595.                     ln->ln_MinNode.mln_Succ != NULL ;
  5596.                     ln = (struct LockNode *)ln->ln_MinNode.mln_Succ)
  5597.                 {
  5598.                     D(("  name='%s'",ln->ln_FullName));
  5599.                     D(("  mode=%ld",ln->ln_FileLock.fl_Access));
  5600.                     D((""));
  5601.                 }
  5602.             }
  5603.         }
  5604.         #endif /* DEBUG */
  5605.  
  5606.         if(signals & SIGBREAKF_CTRL_C)
  5607.             Quit = TRUE;
  5608.  
  5609.         if(Quit)
  5610.         {
  5611.             if(IsListEmpty((struct List *)&FileList) && IsListEmpty((struct List *)&LockList))
  5612.             {
  5613.                 SHOWMSG("no locks or files pending; quitting");
  5614.                 done = TRUE;
  5615.             }
  5616.             else
  5617.             {
  5618.                 SHOWMSG("locks or files still pending; cannot quit yet");
  5619.             }
  5620.         }
  5621.     }
  5622.     while(NOT done);
  5623.  
  5624.     if(sign_off)
  5625.         Printf("stopped.\n");
  5626.  
  5627.     LEAVE();
  5628. }
  5629.